gRPC-Web: Bringing gRPC to Browser Applications

gRPC-Web enables browser clients to call gRPC services. This is particularly exciting for Blazor WebAssembly, where you can now use the same strongly-typed gRPC contracts on both server and client. Let’s explore how to set this up with .NET 5.

Why gRPC-Web?

Standard gRPC requires HTTP/2 with trailers, which browsers don’t fully support. gRPC-Web overcomes this by using a protocol that works over HTTP/1.1. The trade-off is that bidirectional streaming isn’t supported (server streaming works).

flowchart LR
    subgraph Browser
        BLAZOR[Blazor WASM]
        GRPC_CLIENT[gRPC-Web Client]
    end
    
    subgraph Server
        GRPC_WEB[gRPC-Web Middleware]
        GRPC_SVC[gRPC Service]
    end
    
    BLAZOR --> GRPC_CLIENT
    GRPC_CLIENT -->|HTTP 1.1/2| GRPC_WEB
    GRPC_WEB --> GRPC_SVC
    
    style BLAZOR fill:#E8F5E9,stroke:#2E7D32
    style GRPC_WEB fill:#E3F2FD,stroke:#1565C0

Server Setup

// Program.cs / Startup.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

var app = builder.Build();

app.UseGrpcWeb();  // Enable gRPC-Web

app.MapGrpcService<GreeterService>()
   .EnableGrpcWeb();  // Per-service opt-in

app.MapGrpcService<OrderService>()
   .EnableGrpcWeb()
   .RequireCors("AllowBlazor");  // If CORS needed

app.Run();

Proto Definition

// greeter.proto
syntax = "proto3";

option csharp_namespace = "GrpcService";

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
  rpc SayHelloStream (HelloRequest) returns (stream HelloReply);  // Server streaming works!
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

Blazor WebAssembly Client

// Program.cs
builder.Services.AddScoped(sp =>
{
    var handler = new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler());
    var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
    {
        HttpHandler = handler
    });
    return new Greeter.GreeterClient(channel);
});

// In component
@inject Greeter.GreeterClient Client

@code {
    private string? response;
    
    protected override async Task OnInitializedAsync()
    {
        var reply = await Client.SayHelloAsync(new HelloRequest { Name = "Blazor" });
        response = reply.Message;
    }
}

Benefits Over REST

  • Strong typing: Share .proto contracts, get compile-time safety
  • Efficient: Binary Protobuf smaller than JSON
  • Code generation: Client/server stubs generated automatically
  • Streaming: Server streaming for real-time updates

Key Takeaways

  • gRPC-Web enables gRPC calls from browsers including Blazor WASM
  • Add UseGrpcWeb() middleware and EnableGrpcWeb() per service
  • Use GrpcWebHandler on the client side
  • Server streaming works; bidirectional streaming doesn’t

References


Discover more from C4: Container, Code, Cloud & Context

Subscribe to get the latest posts sent to your email.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.