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

James Newton-King

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

Discussion is closed. Login to edit/delete existing comments.

  • James Hancock 0

    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.

    • Peter Karman 0

      +1 yes please

      • James Newton-KingMicrosoft employee 0

        You’ll find this interesting: gRPC HTTP API – https://github.com/aspnet/AspLabs/tree/master/src/GrpcHttpApi

        To set expectations: gRPC HTTP API is a project I played around with while traveling, and I put up on GitHub because some people wanted to try it out. While I think it is a cool idea, it is super experimental, and we (ASP.NET team) don’t have plans to work on it right now. However community contributions are welcome. And if there is a lot of interest in gRPC+REST then we could look at investing in it.

        GitHub issue about it – https://github.com/grpc/grpc-dotnet/issues/167

  • James Brantly 0

    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 0

    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.

  • Zeeshan Hirani 0

    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.

    • Shimmy Weitzhandler 0

      Same question here.
      WOW Zeeshan are you alive? Used to read your articles and books. Good to see you around! What’s your handle?

      I also wonder what about inheritance, validation logic or other shared entity implementations.

    • James Newton-KingMicrosoft employee 0

      That’s outside the scope of the work we are doing.

      protobuf-net uses C# types as the contract. They might support it, or consider supporting it. You could ask about that feature here – https://github.com/protobuf-net/protobuf-net

  • David Inggs 0

    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.

    • Olivier HOUSSIN 0

      I have the same behavior on my program, impossible to operate the server streaming mode, I hope it will be implemented before the release of version 2.27

  • Anthony GIRETTI 0

    Hi!

    I was impatient to use gRPC in a Browser, gRPC-Web with ASP.NET Core made it real, I have been able to build an Angular 8 app with gRPC-Web.
    Thank you! I really enjoy the feature, I would love to use that in production.

    Here is the repository of the Angular 8 app: https://github.com/AnthonyGiretti/angular8-grpc-aspnetcore3-1-demo

  • Luke Kenyon 0

    Hi, You mention that gRPC-Web will work with IIS before I commit some time what would be the correct way of hosting the gRPC Service on IIS?

    • James Newton-KingMicrosoft employee 0

      There are no special requirements for gRPC-Web on IIS. It works with HTTP/1.1 and HTTP/2. It works with TLS and without TLS.

      • David Graham 0

        I have tested this in IIS, but the client just waits on SayHelloAsync. If you shutdown the server however then you get 404.

  • Will Blackburn 0

    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 0

    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 0

    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

Feedback usabilla icon