gRPC And Blazor WebAssembly App In .NET 6

What is gRPC?

gRPC has been developed by Google. It is a high performance Remote Procedure Call RPC framework. It is an open source framework. This framework supports client server communication by providing automatic client side code generation based on protobuf contract. It can be useful for a large number of cross platform application integration developed in multiple programming languages and platforms. Following are the core capabilities,

  1. Bi-Directional communication support.
    1. Client Streaming
    2. Server Streaming
    3. Duplex Streaming
  2. Supports HTTP/2.
  3. Supports 11 programming languages right now.
  4. Efficient client side code generation.
  5. Standard message contract (.proto) is available.

What is Blazor WebAssembly App?

Blazor is high performance web framework developed by Microsoft that lets developer write application using C# and allows applications to run in modern web browsers using WebAssembly technology. WebAssembly technology is almost 1.5 times faster than Javascript. It is an open source framework. To work with this framework developers don’t have to learn Javascript very extensively. The knowledge of C# is sufficient and developers can develop Single Page Applications very rapidly. Following are the core capabilities,

  1. Component Driven architecture.
  2. Can share code with .NET Standard.
  3. Supports javascript interop.
  4. Supports server rendering using Blazor Server.
  5. Good support for Globalization and Localization.

Why Integrate Blazor WebAssembly and gRPC?

This can be ideal choice for .NET developer as we can use C# to build applications faster with the modern applications framework ecosystem. Blazor is a fast WebAssembly based Single Page Application framework which allows developer to write applications in .NET ecosystem by using C# code. WebAssembly is the future and Blazor WebAssembly is a good candidate to get this accomplished. To develop single page applications we need a good amount of interaction with Server. When building server APIs we need to write a lot of integration code. gRPC allows us to develop application backend in C# based on application contracts our client side code gets auto generated. This saves a lot of effort and builds high performance applications.

Code walkthrough

Our project works like this,

gRPC and Blazor WebAssembly App in .NET 6

Firstly we create a proto file. This proto file is a contract used by both client and server as a standard format to exchange data. Below is our message contract in the protocol buffer format. This will be placed in the Protos folder in server and client project. 

Protos/car.proto

syntax = "proto3";
option csharp_namespace = "GrpcClient";
package grpccars;
service Car {
    rpc GetCars(CarsRequest) returns(CarsResponse);
}
message CarsRequest {}
message CarsResponse {
    repeated CarResponse cars = 1;
}
message CarResponse {
    string name = 1;
}

Now, In the server project add below packages. These packages are essential to generate server side implementation.

<ItemGroup>
    <PackageReference Include="Grpc.AspNetCore" Version="2.46.0" />
    <PackageReference Include="Grpc.AspNetCore.Web" Version="2.46.0" />
</ItemGroup>

Server.csproj should have below code, this will allow scaffolding of server side code which we will override.

<ItemGroup>
    <Protobuf Include="Protos\car.proto" GrpcServices="Server" />
</ItemGroup>

Now, we will implement a simple method that will return a list of cars. This code is used to override and implement the message contract code. 

CarsService.cs

using Grpc.Core;
using Grpc.Net.Client;
using GrpcClient;
namespace Grpc.Server {
    public class CarsService: Car.CarBase {
        public override async Task < CarsResponse > GetCars(CarsRequest request, ServerCallContext context) {
            CarsResponse response = new CarsResponse();
            response.Cars.Add(new CarResponse {
                Name = "Honda City"
            });
            response.Cars.Add(new CarResponse {
                Name = "Hyundai Kona"
            });
            response.Cars.Add(new CarResponse {
                Name = "Ford Endeavour"
            });
            return response;
        }
    }
}

In Program.cs we will add CORS policy and gRPC service middleware. Along with this we will add support for gRPC web that will allow apps to use HTTP/1.1 protocol to communicate. This support is required as web browsers do not support HTTP/2 protocol right now. With HTTP/1.1 support we will be able receive calls from blazor web assembly.

Progarm.cs

using Grpc.Server;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc(options => {
    options.EnableDetailedErrors = true;
    options.MaxReceiveMessageSize = 2 * 1024 * 1024; // 2 MB
    options.MaxSendMessageSize = 5 * 1024 * 1024; // 5 MB
});
builder.Services.AddCors(setupAction => {
    setupAction.AddDefaultPolicy(policy => {
        policy.AllowAnyHeader().AllowAnyOrigin().AllowAnyMethod().WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding");
    });
});
var app = builder.Build();
app.UseCors();
app.UseRouting();
app.UseGrpcWeb(new GrpcWebOptions {
    DefaultEnabled = true
});
app.UseEndpoints(endpoints => {
    endpoints.MapGrpcService < CarsService > ();
});
app.Run();

In client projects add below packages, these packages are essential for code generation and protobuf support to interact with the server.

<ItemGroup>
  <PackageReference Include="Grpc.Net.Client.Web" Version="2.46.0" />
  <PackageReference Include="Google.Protobuf" Version="3.21.1" />
  <PackageReference Include="Grpc.Net.Client" Version="2.46.0" />
  <PackageReference Include="Grpc.Tools" Version="2.46.3">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
  </PackageReference>
</ItemGroup>

Make sure Client.csproj has the following code, this is for client side so GrpcServices=Client. In the above code we had GrpcServices=Server for Server side.

<ItemGroup>
	  <Protobuf Include="Protos\car.proto" GrpcServices="Client" />
</ItemGroup>

This is sample code to send RPC calls to the server endpoint.

Index.razor

@page "/"

<PageTitle>Index</PageTitle>

<h1>Cars from Grpc Service</h1>

@foreach(var car in model.Cars)
{
    <p>Name : @car.Name</p>
}    
@code {
    private GrpcClient.CarsResponse model = new GrpcClient.CarsResponse();
    protected override async Task OnInitializedAsync() {
        using
        var channel = GrpcChannel.ForAddress("https://localhost:7272/", new GrpcChannelOptions {
            HttpHandler = new GrpcWebHandler(new HttpClientHandler())
        });
        var client = new GrpcClient.Car.CarClient(channel);
        model = await client.GetCarsAsync(new GrpcClient.CarsRequest {});
    }
}

Run webassembly app and Grpc Server, below is the screenshot for reference.

gRPC and Blazor WebAssembly App in .NET 6

That’s it! Now we can effortlessly develop our applications very rapidly. This will save our lot of boilerplate code for writing integrations and we can focus purely on business logic. I have uploaded code for reference. Please feel free to explore.