--- title: Use gRPC in browser apps author: jamesnk description: Learn how to configure gRPC services on ASP.NET Core to be callable from browser apps using gRPC-Web. monikerRange: '>= aspnetcore-3.0' ms.author: jamesnk ms.date: 06/30/2020 no-loc: [Home, Privacy, Kestrel, appsettings.json, "ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR] uid: grpc/browser --- # Use gRPC in browser apps By [James Newton-King](https://twitter.com/jamesnk) Learn how to configure an existing ASP.NET Core gRPC service to be callable from browser apps, using the [gRPC-Web](https://github.com/grpc/grpc/blob/2a388793792cc80944334535b7c729494d209a7e/doc/PROTOCOL-WEB.md) protocol. gRPC-Web allows browser JavaScript and Blazor apps to call gRPC services. It's not possible to call an HTTP/2 gRPC service from a browser-based app. gRPC services hosted in ASP.NET Core can be configured to support gRPC-Web alongside HTTP/2 gRPC. For instructions on adding a gRPC service to an existing ASP.NET Core app, see [Add gRPC services to an ASP.NET Core app](xref:grpc/aspnetcore#add-grpc-services-to-an-aspnet-core-app). For instructions on creating a gRPC project, see . ## gRPC-Web in ASP.NET Core vs. Envoy There are two choices for how to add gRPC-Web to an ASP.NET Core app: * Support gRPC-Web alongside gRPC HTTP/2 in ASP.NET Core. This option uses middleware provided by the `Grpc.AspNetCore.Web` package. * Use the [Envoy proxy's](https://www.envoyproxy.io/) gRPC-Web support to translate gRPC-Web to gRPC HTTP/2. The translated call is then forwarded onto the ASP.NET Core app. There are pros and cons to each approach. If an app's environment is already using Envoy as a proxy, it might make sense to also use Envoy to provide gRPC-Web support. For a basic solution for gRPC-Web that only requires ASP.NET Core, `Grpc.AspNetCore.Web` is a good choice. ## Configure gRPC-Web in ASP.NET Core gRPC services hosted in ASP.NET Core can be configured to support gRPC-Web alongside HTTP/2 gRPC. gRPC-Web does not require any changes to 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](https://www.nuget.org/packages/Grpc.AspNetCore.Web) package. * Configure the app to use gRPC-Web by adding `UseGrpcWeb` and `EnableGrpcWeb` to *Startup.cs*: [!code-csharp[](~/grpc/browser/sample/Startup.cs?name=snippet_1&highlight=10,14)] The preceding code: * Adds the gRPC-Web middleware, `UseGrpcWeb`, after routing and before endpoints. * Specifies the `endpoints.MapGrpcService()` method supports gRPC-Web with `EnableGrpcWeb`. Alternatively, the gRPC-Web middleware can be configured so all services support gRPC-Web by default and `EnableGrpcWeb` isn't required. Specify `new GrpcWebOptions { DefaultEnabled = true }` when the middleware is added. [!code-csharp[](~/grpc/browser/sample/AllServicesSupportExample_Startup.cs?name=snippet_1&highlight=12)] > [!NOTE] > There is a known issue that causes gRPC-Web to fail when [hosted by HTTP.sys](xref:fundamentals/servers/httpsys) in .NET Core 3.x. > > A workaround to get gRPC-Web working on HTTP.sys is available [here](https://github.com/grpc/grpc-dotnet/issues/853#issuecomment-610078202). ### gRPC-Web and CORS Browser security prevents a web page from making requests to a different domain than the one that served the web page. This restriction applies to making gRPC-Web calls with browser apps. For example, a browser app served by `https://www.contoso.com` is blocked from calling gRPC-Web services hosted on `https://services.contoso.com`. Cross Origin Resource Sharing (CORS) can be used to relax this restriction. To allow a browser app to make cross-origin gRPC-Web calls, set up [CORS in ASP.NET Core](xref:security/cors). Use the built-in CORS support, and expose gRPC-specific headers with . [!code-csharp[](~/grpc/browser/sample/CORS_Startup.cs?name=snippet_1&highlight=5-11,19,24)] The preceding code: * Calls `AddCors` to add CORS services and configures a CORS policy that exposes gRPC-specific headers. * Calls `UseCors` to add the CORS middleware after routing and before endpoints. * Specifies the `endpoints.MapGrpcService()` method supports CORS with `RequiresCors`. ### gRPC-Web and streaming Traditional gRPC over HTTP/2 supports streaming in all directions. gRPC-Web offers limited support for streaming: * gRPC-Web browser clients don't support calling client streaming and bidirectional streaming methods. * ASP.NET Core gRPC services hosted on Azure App Service and IIS don't support bidirectional streaming. When using gRPC-Web, we only recommend the use of unary methods and server streaming methods. ## Call gRPC-Web from the browser Browser apps can use gRPC-Web to call gRPC services. There are some requirements and limitations when calling gRPC services with gRPC-Web from the browser: * The server must have been configured to support gRPC-Web. * Client streaming and bidirectional streaming calls aren't supported. Server streaming is supported. * Calling gRPC services on a different domain requires [CORS](xref:security/cors) to be configured on the server. ### JavaScript gRPC-Web client There is a JavaScript gRPC-Web client. For instructions on how to use gRPC-Web from JavaScript, see [write JavaScript client code with gRPC-Web](https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway/examples/helloworld#write-client-code). ### Configure gRPC-Web with the .NET gRPC client The .NET gRPC client can be configured to make gRPC-Web calls. This is useful for [Blazor WebAssembly](xref:blazor/index#blazor-webassembly) apps, which are hosted in the browser and have the same HTTP limitations of JavaScript code. Calling gRPC-Web with a .NET client is [the same as HTTP/2 gRPC](xref:grpc/client). The only modification is how the channel is created. To use gRPC-Web: * Add a reference to the [Grpc.Net.Client.Web](https://www.nuget.org/packages/Grpc.Net.Client.Web) package. * Ensure the reference to [Grpc.Net.Client](https://www.nuget.org/packages/Grpc.Net.Client) package is 2.29.0 or greater. * Configure the channel to use the `GrpcWebHandler`: [!code-csharp[](~/grpc/browser/sample/Handler.cs?name=snippet_1)] The preceding code: * Configures a channel to use gRPC-Web. * Creates a client and makes a call using the channel. `GrpcWebHandler` has the following configuration options: * **InnerHandler**: The underlying that makes the gRPC HTTP request, for example, `HttpClientHandler`. * **GrpcWebMode**: An enumeration type that specifies whether the gRPC HTTP request `Content-Type` is `application/grpc-web` or `application/grpc-web-text`. * `GrpcWebMode.GrpcWeb` configures content to be sent without encoding. Default value. * `GrpcWebMode.GrpcWebText` configures content to be base64 encoded. Required for server streaming calls in browsers. * **HttpVersion**: HTTP protocol `Version` used to set [HttpRequestMessage.Version](xref:System.Net.Http.HttpRequestMessage.Version) on the underlying gRPC HTTP request. gRPC-Web doesn't require a specific version and doesn't override the default unless specified. > [!IMPORTANT] > Generated gRPC clients have sync and async methods for calling unary methods. For example, `SayHello` is sync and `SayHelloAsync` is async. Calling a sync method in a Blazor WebAssembly app will cause the app to become unresponsive. Async methods must always be used in Blazor WebAssembly. ### Use gRPC client factory with gRPC-Web A gRPC-Web compatible .NET client can be created using the [gRPC client factory](xref:grpc/clientfactory). To use gRPC-Web with client factory: * Add package references to the project file for the following packages: * [Grpc.Net.Client.Web](https://www.nuget.org/packages/Grpc.Net.Client.Web) * [Grpc.Net.ClientFactory](https://www.nuget.org/packages/Grpc.Net.ClientFactory) * Register a gRPC client with dependency injection (DI) using the generic `AddGrpcClient` extension method. In a Blazor WebAssembly app, services are registered with DI in `Program.cs`. * Configure `GrpcWebHandler` using the extension method. ```csharp builder.Services .AddGrpcClient(options => { options.Address = new Uri("https://localhost:5001"); }) .ConfigurePrimaryHttpMessageHandler( () => new GrpcWebHandler(new HttpClientHandler())); ``` For more information, see . ## Additional resources * [gRPC for Web Clients GitHub project](https://github.com/grpc/grpc-web) * *