A new experiment: Call .NET gRPC services from the browser with gRPC-Web

Avatar

James

I’m excited to announce experimental support for gRPC-Web with .NET. gRPC-Web allows gRPC to be called from browser-based apps like JavaScript SPAs or Blazor WebAssembly apps.

gRPC-Web for .NET promises to bring many of gRPC’s great features to browser apps:

  • Strongly-typed code-generated clients
  • Compact Protobuf messages
  • Server streaming

What is gRPC-Web

It is impossible to implement the gRPC HTTP/2 spec in the browser because there is no browser API with enough fine-grained control over HTTP requests. gRPC-Web solves this problem by being compatible with HTTP/1.1 and HTTP/2.

gRPC-Web is not a new technology. There is a stable gRPC-Web JavaScript client, and a proxy for translating between gRPC and gRPC-Web for services. The new experimental packages allow an ASP.NET Core gRPC app to support gRPC-Web without a proxy, and allow the .NET Core gRPC client to call gRPC-Web services. (great for Blazor WebAssembly apps!)

New opportunites with gRPC-Web

  • Call ASP.NET Core gRPC apps from the browser – Browser APIs can’t call gRPC HTTP/2. gRPC-Web offers a compatible alternative.
    • JavaScript SPAs
    • .NET Blazor Web Assembly apps
  • Host ASP.NET Core gRPC apps in IIS and Azure App Service – Some servers, such as IIS and Azure App Service, currently can’t host gRPC services. While this is actively being worked on, gRPC-Web offers an interesting alternative that works in every environment today.
  • Call gRPC from non-.NET Core platforms – Some .NET platforms HttpClient doesn’t support HTTP/2. gRPC-Web can be used to call gRPC services on these platforms (e.g. Blazor WebAssembly, Xamarin).

Note that there is a small performance cost to gRPC-Web, and two gRPC features are no longer supported: client streaming and bi-directional streaming. (server streaming is still supported!)

Server gRPC-Web instructions

If you are new to gRPC in .NET, there is a simple tutorial to get you started.

gRPC-Web does not require any changes to your services, the only modification is startup configuration. To enable gRPC-Web with an ASP.NET Core gRPC service, add a reference to the Grpc.AspNetCore.Web package. Configure the app to use gRPC-Web by adding AddGrpcWeb(...) and UseGrpcWeb() in the startup file:

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc();
}

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    // Add gRPC-Web middleware after routing and before endpoints
    app.UseGrpcWeb();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb();
    });
}

Some additional configuration may be required to call gRPC-Web from the browser, such as configuring the app to support CORS.

Client gRPC-Web instructions

The JavaScript gRPC-Web client has instructions for setting up a gRPC-Web client to use in browser JavaScript SPAs.

Calling gRPC-Web with a .NET client is the same as regular gRPC, the only modification is how the channel is created. To enable gRPC-Web, add a reference to the Grpc.Net.Client.Web package. Configure the channel to use the GrpcWebHandler:

// Configure a channel to use gRPC-Web
var handler = new GrpcWebHandler(GrpcWebMode.GrpcWebText, new HttpClientHandler());
var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
    {
        HttpClient = new HttpClient(handler)
    });

var client = Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(new GreeterRequest { Name = ".NET" });

To see gRPC-Web with .NET in action, take a moment to read a great blog post written by Steve Sanderson that uses gRPC-Web in Blazor WebAssembly.

Try gRPC-Web with ASP.NET Core today

Preview packages are on NuGet:

Documentation for using gRPC-Web with .NET Core can be found here.

gRPC-Web for .NET is an experimental project, not a committed product. We want to test that our approach to implementing gRPC-Web works, and get feedback on whether this approach is useful to .NET developers compared to the traditional way of setting up gRPC-Web via a proxy. Please add your feedback here or at the https://github.com/grpc/grpc-dotnet to ensure we build something that developers like and are productive with.

Thanks!

23 comments

Comments are closed. Login to edit/delete your existing comments

  • Avatar
    James Hancock

    I’d really love to see a merge of standard WebAPI REST and gRPC so that we can have cross combability.

    I.e. using this and proto files, the server side endpoints would generate functions that are annotated for both REST and gRPC. (since server streaming is also supported in REST)

    Then on the client you can opt to generate client libraries however you wish from proto. This would really improve everything end to end and allow us to support old and new at the same time.

  • Avatar
    James Brantly

    This is awesome! I’ve been waiting/hoping that support for something like this would be coming soon (I did not want to be forced to use envoy). Just wanted to show my support and appreciation. Thanks!

  • Brad Triebwasser
    Brad Triebwasser

    Looks great! Are there any plans to support model (proto) validation? gRPC looks promising but the lack of model validation is which normal ASP/ViewModels provides is making me hesitant to make the switch.

  • Avatar
    Zeeshan Hirani

    Is it possible to generate proto files from my C# contract. I am new to GRPC but not new to C#. I would like the ability define my C# contract and generate a proto file from that.

  • Avatar
    David Inggs

    Thanks for the article, it was very helpful.

    I’ve been trying to get a Grpc Server to Stream to a Blazor WebAssembly application without luck. The examples for Blazer only show a Unary call, not a streaming example.

    My attempts at adding this show a stream coming through in the network (via Chrome dev tools) but the code isn’t picking it up in the Blazor Web app. I’ve made sure the HttpClient is in GrpcWebText mode so should be browser compatible.

    Any suggestions appreciated.

  • Avatar
    Will Blackburn

    We’ve already got some gRPC clients (Dotnet Core Worker Service) running using reverse proxies and Kestrel, but are keen to switch to App Service Plans (or even a VM and IIS) as this is the business standard approach. As such, this post was a great bit of news and so we quickly set about converting the start up in both client and server to support it.

    Having deployed to both VM running IIS and then an Application Service plan we keep getting met with the same error message, I’m fairly sure it’s to do with IIS configuration but I can’t find anything that helps with the issue.

    I opened a question on the GitHub page rather than flooding the comment here with error messages https://github.com/grpc/grpc-dotnet/issues/759

  • Rick Way
    Rick Way

    Is there a sample project for this? In my attempt, the server is returning 200 after a couple of seconds, but the client is reporting a 404 after a few milliseconds. I’m assuming I’ve got something setup wrong, but I’ve been scratching my head over it.

  • Joacim Wall
    Joacim Wall

    Hi i try to use this from Xamarin forms and it work when i publish the server to azure but i am not able to debug on local dev computer from Android.
    i have tested to follow the instruction on thttps://go.microsoft.com/fwlink/?linkid=2099682.

    so i add this on the client side.
    handlerdev = new HttpClientHandler();
    handlerdev.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
    AppContext.SetSwitch(“System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport”, true);

    string urlDev = "https://10.0.2.2:5001";
    handler = new GrpcWebHandler(GrpcWebMode.GrpcWebText, handlerdev);

    channel = GrpcChannel.ForAddress(urlDev, new GrpcChannelOptions
    {
    HttpClient = new HttpClient(handler)

    });

    GrpcClient = new Greeter.GreeterClient(channel);
    var response = GrpcClient.SayHello(new HelloRequest { Name = "Joacim" })

    but get this error on server
    Microsoft.AspNetCore.Server.Kestrel[0]
    HTTP/2 over TLS was not negotiated on an HTTP/2-only endpoint.

    if i turn off the TLS
    public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
    webBuilder.ConfigureKestrel(options =>
    {
    // Setup a HTTP/2 endpoint without TLS.
    options.ListenLocalhost(5001, o => o.Protocols =
    HttpProtocols.Http2);
    });

    webBuilder.UseStartup<Startup>();
    });

    I get this on the client side

    Grpc.Core.RpcException: ‘Status(StatusCode=Internal, Detail=”Error starting gRPC call: The SSL connection could not be established, see inner exception.”)’
    change the url to http:
    Grpc.Core.RpcException: ‘Status(StatusCode=Internal, Detail=”Error starting gRPC call: An error occurred while sending the request.”)’

    is there any solution to be able to local debug from android to local grpc server?

    resolved by change to
    “Kestrel”: {
    “EndpointDefaults”: {
    “Protocols”: “Https”
    }
    appsettings.joson for development

    Regards Joacim Wall