{"id":108408,"date":"2020-01-27T14:00:39","date_gmt":"2020-01-27T14:00:39","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/aspnet\/?p=23102"},"modified":"2020-01-27T14:00:39","modified_gmt":"2020-01-27T14:00:39","slug":"a-new-experiment-call-net-grpc-services-from-the-browser-with-grpc-web","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2020\/01\/27\/a-new-experiment-call-net-grpc-services-from-the-browser-with-grpc-web\/","title":{"rendered":"A new experiment: Call .NET gRPC services from the browser with gRPC-Web"},"content":{"rendered":"<div class=\"row justify-content-center\">\n<div class=\"col-md-4\">\n<div><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.sickgaming.net\/blog\/wp-content\/uploads\/2020\/02\/a-new-experiment-call-net-grpc-services-from-the-browser-with-grpc-web.png\" width=\"58\" height=\"58\" alt=\"Avatar\" class=\"avatar avatar-58 wp-user-avatar wp-user-avatar-58 photo avatar-default\"><\/p>\n<p>James<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"entry-meta\">\n<p>January 27th, 2020<\/p>\n<\/p><\/div>\n<p><!-- .entry-meta --> <\/p>\n<p>I\u2019m 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.<\/p>\n<p>gRPC-Web for .NET promises to bring many of gRPC\u2019s great features to browser apps:<\/p>\n<ul>\n<li>Strongly-typed code-generated clients<\/li>\n<li>Compact Protobuf messages<\/li>\n<li>Server streaming<\/li>\n<\/ul>\n<h2>What is gRPC-Web<\/h2>\n<p>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. <a href=\"https:\/\/github.com\/grpc\/grpc\/blob\/master\/doc\/PROTOCOL-WEB.md\">gRPC-Web<\/a> solves this problem by being compatible with HTTP\/1.1 and HTTP\/2.<\/p>\n<p>gRPC-Web is not a new technology. There is a stable <a href=\"https:\/\/github.com\/grpc\/grpc-web\">gRPC-Web JavaScript client<\/a>, and a <a href=\"https:\/\/blog.envoyproxy.io\/envoy-and-grpc-web-a-fresh-new-alternative-to-rest-6504ce7eb880\">proxy for translating between gRPC and gRPC-Web<\/a> for services. The new experimental packages allow an ASP.NET Core gRPC app to support gRPC-Web <strong>without<\/strong> a proxy, and allow the .NET Core gRPC client to call gRPC-Web services. (great for Blazor WebAssembly apps!)<\/p>\n<h2>New opportunites with gRPC-Web<\/h2>\n<ul>\n<li><strong>Call ASP.NET Core gRPC apps from the browser<\/strong> \u2013 Browser APIs can\u2019t call gRPC HTTP\/2. gRPC-Web offers a compatible alternative.\n<ul>\n<li>JavaScript SPAs<\/li>\n<li>.NET Blazor Web Assembly apps<\/li>\n<\/ul>\n<\/li>\n<li><strong>Host ASP.NET Core gRPC apps in IIS and Azure App Service<\/strong> \u2013 Some servers, such as IIS and Azure App Service, currently can\u2019t host gRPC services. While this is actively being worked on, gRPC-Web offers an interesting alternative that works in every environment today.<\/li>\n<li><strong>Call gRPC from non-.NET Core platforms<\/strong> \u2013 Some .NET platforms <code>HttpClient<\/code> doesn\u2019t support HTTP\/2. gRPC-Web can be used to call gRPC services on these platforms (e.g. Blazor WebAssembly, Xamarin).<\/li>\n<\/ul>\n<p>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!)<\/p>\n<h2>Server gRPC-Web instructions<\/h2>\n<p>If you are new to gRPC in .NET, there is a <a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/tutorials\/grpc\/grpc-start\">simple tutorial to get you started<\/a>.<\/p>\n<p>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 <em>Grpc.AspNetCore.Web<\/em> package. Configure the app to use gRPC-Web by adding <code>AddGrpcWeb(...)<\/code> and <code>UseGrpcWeb()<\/code> in the startup file:<\/p>\n<p><em>Startup.cs<\/em><\/p>\n<pre><code class=\"csharp\">public void ConfigureServices(IServiceCollection services)\n{ services.AddGrpc();\n} public void Configure(IApplicationBuilder app)\n{ app.UseRouting(); \/\/ Add gRPC-Web middleware after routing and before endpoints app.UseGrpcWeb(); app.UseEndpoints(endpoints =&gt; { endpoints.MapGrpcService&lt;GreeterService&gt;().EnableGrpcWeb(); });\n}\n<\/code><\/pre>\n<p>Some additional configuration may be required to call gRPC-Web from the browser, such as configuring the app to support CORS.<\/p>\n<h2>Client gRPC-Web instructions<\/h2>\n<p>The JavaScript gRPC-Web client has <a href=\"https:\/\/github.com\/grpc\/grpc-web\/tree\/master\/net\/grpc\/gateway\/examples\/helloworld#write-client-code\">instructions<\/a> for setting up a gRPC-Web client to use in browser JavaScript SPAs.<\/p>\n<p>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 <em>Grpc.Net.Client.Web<\/em> package. Configure the channel to use the <code>GrpcWebHandler<\/code>:<\/p>\n<pre><code class=\"csharp\">\/\/ Configure a channel to use gRPC-Web\nvar handler = new GrpcWebHandler(GrpcWebMode.GrpcWebText, new HttpClientHandler());\nvar channel = GrpcChannel.ForAddress(\"https:\/\/localhost:5001\", new GrpcChannelOptions { HttpClient = new HttpClient(handler) }); var client = Greeter.GreeterClient(channel);\nvar response = await client.SayHelloAsync(new GreeterRequest { Name = \".NET\" });\n<\/code><\/pre>\n<p>To see gRPC-Web with .NET in action, take a moment to read a great blog post written by Steve Sanderson that uses <a href=\"https:\/\/blog.stevensanderson.com\/2020\/01\/15\/2020-01-15-grpc-web-in-blazor-webassembly\/\">gRPC-Web in Blazor WebAssembly<\/a>.<\/p>\n<h2>Try gRPC-Web with ASP.NET Core today<\/h2>\n<p>Preview packages are on NuGet:<\/p>\n<p>Documentation for using gRPC-Web with .NET Core can be found <a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/grpc\/browser\">here<\/a>.<\/p>\n<p>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 <a href=\"https:\/\/github.com\/grpc\/grpc-dotnet\">https:\/\/github.com\/grpc\/grpc-dotnet<\/a> to ensure we build something that developers like and are productive with.<\/p>\n<p>Thanks!<\/p>\n<div class=\"authorinfoarea\">\n<div><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.sickgaming.net\/blog\/wp-content\/uploads\/2020\/02\/a-new-experiment-call-net-grpc-services-from-the-browser-with-grpc-web-1.png\" width=\"96\" height=\"96\" alt=\"Avatar\" class=\"avatar avatar-96 wp-user-avatar wp-user-avatar-96 photo avatar-default\"><\/div>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>James January 27th, 2020 I\u2019m 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\u2019s great features to browser apps: Strongly-typed code-generated clients Compact Protobuf messages Server streaming What is gRPC-Web [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":108409,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[66],"tags":[80,67,120],"class_list":["post-108408","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microsoft-webdev","tag-aspnet","tag-aspnetcore","tag-blazor"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/108408","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=108408"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/108408\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media\/108409"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=108408"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=108408"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=108408"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}