Search code examples
c#.netgrpcdotnet-aspire

How to communicate with a gRPC API from a Blazor app using .NET Aspire?


I'm currently experimenting with .NET Aspire. According to docs, Aspire is used to streamline connections and communication between services in applications. One of the features that Aspire offers is the ease of communications between services, by giving each a special name that can be resolved via them, removing the need to manually set the ports and match the addresses for making services connect.

In the .NET Aspire Quickstart Documentation, is it explained that you can set custom names to your projects in the AppHost Project's Program.cs file like this:

var builder = DistributedApplication.CreateBuilder (args);

var usersApi = builder
    .AddProject<Projects.Bargeh_Users_API> ("usersapi"); // Setting the name "usersapi" to the project


builder.AddProject<Projects.Bargeh_Main_Wapp> ("bargehmainwapp")
    .WithReference (usersApi)
    .WithReference (smsApi)
    .WithLaunchProfile ("https");

builder.Build ().Run ();

Again from the documentation, you can add this code in the project that wants to have access to the other service and let Aspire know that you need that service and resolve that URL for you:

builder.Services.AddHttpClient<UsersApiHttpClientProvider>(
    static client=> client.BaseAddress = new("http://usersapi"));

Then, you can inject UsersApiHttpClientProvider wherever you want and make use of it.

This approach works, but only for accessing APIs that are open to normal HTTP requests. The problem is, that the UsersApi that I'm using is not a REST API, but it's a GRPC service. I can connect to the API and send requests to it, but I'm unable to send real GRPC requests.

My question is, how can I make my client projects (a Blazor Web App in this case) connect to my backend GRPC Services using Grpc.Net packages, while the connection between them is established by .NET Aspire?


Solution

  • Code of AppHost for me looks like following:

    using System.Net.Sockets;
    
    var builder = DistributedApplication.CreateBuilder(args);
    
    var server = builder.AddProject<Projects.Server>("server");
    
    var apiservice = builder.AddProject<Projects.AspireHost_ApiService>("apiservice")
        .WithReference(server);
        
    builder.AddProject<Projects.AspireHost_Web>("webfrontend")
        .WithReference(apiservice);
    
    builder.Build().Run();
    

    Here Projects.Server is an application with GRPC server.

    A client application, in my case AspireHost_ApiService, should reference Grpc.Net.ClientFactory package

    Then adding of a GRPC client should look like:

    builder.Services
        .AddGrpcClient<ServerService.ServerServiceClient>(
            options =>
            {
                options.Address = new Uri("http://server");
            }
        );
    

    And usage might look like:

    api.MapGet(
        "/",
        async (ServerService.ServerServiceClient client) =>
        {
            ...
        }
    );
    

    That works at least from Aspire Preview 6 where I actually tested it.