在 Blazor WebAssembly 中使用 gRPC-Web

对于单页面应用程序,gRPC-Web 是 JSON-over-HTTP 的一种方便、高性能的替代方案。

如果你已经了解关于 gRPC 和 gRPC-Web 的一切,你可以跳到 添加 gRPC 服务到一个Blazor WebAssembly 应用程序 一节。如果你只是想要一些简单的 Blazor WebAssembly + gRPC-Web 应用程序,请看这个仓库 https://github.com/SteveSandersonMS/BlazorGrpcSamples。

现状

与其他所有基于浏览器的单页应用程序(SPA)技术一样,在 Blazor WebAssembly 中,数据交互和触发服务器端操作的最常见方式是 JSON-over-HTTP。它很简单:客户端使用预先约定的 HTTP 方法向某个预先约定的 URL 发出 HTTP 请求,然后服务器执行操作并使用预先约定的 HTTP 状态码和预先约定格式的 JSON 数据进行应答。

这种方法通常很有效,这样做的人往往能过上充实的生活。然而,它也有两个显而易见的弱点:

  • JSON 是一种非常冗长的数据格式,它没有优化带宽。

  • 没有任何机制可以保证所有这些预先约定的 url、HTTP 方法、状态码 等等的细节在服务器和客户端之间实际上是一致的。

什么是 gRPC?

gRPC 是一种远程过程调用(RPC)机制,最初由谷歌开发。对于 SPA,你可以将其视为 JSON-over-HTTP 的替代方案。它直接修复了上面列出的两个弱点:

  • 它被优化为最小的网络流量,发送有效的二进制序列化消息

  • 你可以在编译时保证服务器和客户端对端点的存在、数据的发送和接收形式达成一致,而不需要指定任何URL、状态码 等等。

这是怎么做到的呢?

要编写gRPC服务,你需要编写一个.proto文件,它是一组 RPC 服务及其数据形状的独立于语言的描述。从这里,你可以用任何语言生成强类型的服务器和客户端类,从而保证在编译时符合你的协议。然后在运行时,gRPC 处理(反)序列化数据并以有效的格式(默认为 protobuf )发送/接收消息。

另一个很大的好处是它不是 REST,所以你不必与同事经常争论哪些 HTTP 方法和状态代码在你的场景中是最幸福和幸运的。它只是简单的 RPC,在我们还是小孩子的时候就真情实感想要的。

为什么不是每个人都在他们的 SPA 中使用 gRPC ?

传统上,从基于浏览器的应用程序中使用 gRPC 是不可能的,因为 gRPC 需要 HTTP/2,而且浏览器不公开任何 api,让 JS、WASM 代码直接控制 HTTP/2 请求。

但是现在有一个解决方案!gRPC-Web 是 gRPC的扩展,它使 gRPC 与基于浏览器的代码兼容(从技术上讲,它是通过 HTTP/1.1 请求执行 gRPC 的一种方式)。gRPC-Web 还没有流行起来,因为到目前为止还没有多少服务器或客户端框架提供对它的支持。

ASP.NET Core 从 3.0 版本开始就提供了强大的 gRPC 支持。现在,在此基础上,我们将在服务器和客户端提供对 gRPC-Web的预览支持。如果你想深入了解细节,可以在来自 James Newton-King 的优秀的 pull request 查看全部实现(https://github.com/grpc/grpc-dotnet/pull/695)。

添加 gRPC 服务到一个 Blazor WebAssembly 应用程序

目前还没有这方面的项目模板,所以将 gRPC 支持添加到 Blazor WebAssembly 应用程序需要很多步骤,本文是详细的介绍。但好消息是你只需要做一次这样的设置。当你完成起步与运行起来后,添加更多的 gRPC 端点并调用它们是非常简单的。首先,由于 gRPC-Web 包还没有发布到 NuGet.org,现在你需要添加两个临时的包管理源来获得 nightly 预览。你可以在你的解决方案的根目录下添加NuGet.config文件。希望一两个月后就不需要了。

<?xml version="1.0" encoding="utf-8"?>
<configuration><packageSources><!--To inherit the global NuGet package sources remove the <clear/> line below --><clear /><add key="nuget" value="https://api.nuget.org/v3/index.json" /><add key="gRPC-nightly" value="https://grpc.jfrog.io/grpc/api/nuget/v3/grpc-nuget-dev" /><add key="blazor-nightly" value="https://dotnetfeed.blob.core.windows.net/aspnet-blazor/index.json" /></packageSources>
</configuration>

添加 gRPC 服务到一个托管部署的 Blazor WebAssembly 应用程序

如果你已经在 ASP.NET Core 服务端上托管了一个Blazor WebAssembly 应用程序,默认情况下,你有三个项目:客户端、服务端和共享项目。我发现定义 gRPC 服务最方便的地方是在共享项目中,因为这样生成的类对服务器和客户机都可用。首先,编辑你的共享项目的.csproj添加必要的 gRPC 包引用:

  <ItemGroup><PackageReference Include="Google.Protobuf" Version="3.11.2" /><PackageReference Include="Grpc.Net.Client" Version="2.27.0-dev202001100801" /><PackageReference Include="Grpc.Tools" Version="2.27.0-dev202001081219"><PrivateAssets>all</PrivateAssets><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets></PackageReference></ItemGroup>

如果这些包不能正确恢复,请确保添加了 nightly 源。

现在可以创建.proto文件来定义服务了。例如,在共享项目中添加一个名为greet.proto的文件。包含如下内容:

syntax = "proto3";
option csharp_namespace = "GrpcGreeter";
package greet;service Greeter {rpc SayHello (HelloRequest) returns (HelloReply);
}message HelloRequest {string name = 1;
}message HelloReply {string message = 1;
}

要使gRPC工具从这里生成服务器和客户端类,请进入共享项目的.csproj并添加以下内容:

  <ItemGroup><Protobuf Include="greet.proto" /></ItemGroup>

此时,解决方案应该可以没有错误地编译通过。

从服务端公开gRPC服务

在你的服务器项目中,创建一个名为GreeterService的新类,包含以下内容:

using Grpc.Core;
using GrpcGreeter;public class GreeterService : Greeter.GreeterBase
{public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context){var reply = new HelloReply { Message = $"Hello from gRPC, {request.Name}!" };return Task.FromResult(reply);}
}

这个类继承自 Greeter.GreeterBase,它是从 .proto 文件自动生成的。因此,当你将新断点添加到 .proto 中时,你将有新方法可以在这里进行重写来提供具体实现。

服务端的最后一部分是使用新的 api 将其公开为一个 gRPC-Web 服务。你需要为此引用一个包,因此在你的服务端项目的.csproj中,添加以下包引用:

<PackageReference Include="Grpc.AspNetCore" Version="2.27.0-dev202001100801" />
<PackageReference Include="Grpc.AspNetCore.Web" Version="2.27.0-dev202001100801" />

现在,在你的服务器的Startup.cs文件中,修改ConfigureServices以添加以下行:

  services.AddGrpc();

注意:如果你只打算公开gRPC服务,你可能不再需要MVC控制器,在这种情况下,你可以从下面删除services.AddMvc()endpoints.MapDefaultControllerRoute()

只是在 app.AddRouting(); 的下面添加以下内容,它会处理将传入的gRPC-web请求映射到服务端,使其看起来像 gRPC请求:

  app.UseGrpcWeb();

最后,在app.UseEndpoints语句块中注册你的 gRPC-Web 服务类,并在该语句块的顶部使用以下代码行:

  endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb();

就这样,你的gRPC-Web服务端已经准备好了!

在客户端中使用gRPC服务

在你的客户端项目的.csproj中,你需要添加以下两个 nightly 包的引用:

<PackageReference Include="Grpc.Net.Client.Web" Version="2.27.0-dev202001100801" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.Mono" Version="3.2.0-preview1.20052.1" />

后者是为了修复 Blazor WebAssembly 中的一个问题的变通方案,这个问题将在几周后的下一次预览中得到修复。如果这些包不能正常恢复,请确保添加了 nightly 源。

现在设置你的客户端应用程序的依赖项注入系统,以便能够提供GreeterClient的实例。这将允许你在客户端应用程序的任何位置调用 gRPC 服务。在客户端项目的Startup.cs中的ConfigureServices方法中添加以下内容:

services.AddSingleton(services =>
{// Create a gRPC-Web channel pointing to the backend servervar httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()));var baseUri = services.GetRequiredService<NavigationManager>().BaseUri;var channel = GrpcChannel.ForAddress(baseUri, new GrpcChannelOptions { HttpClient = httpClient });// Now we can instantiate gRPC clients for this channelreturn new Greeter.GreeterClient(channel);
});

需要注意的是Greeter.GreeterClient是从.proto file文件中为你生成的代码。你不必手动实现它!但你还需要添加以下使用语句,使上述代码编译通过:

using GrpcGreeter;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
using Microsoft.AspNetCore.Components;
using System.Net.Http;

我们快完成了!现在有一个可工作的服务端,并希望还有一个可工作的客户端。我们只需要从 UI 调用一些 gRPC 服务。例如,在你的Index.razor文件中,替换成如下内容:

@page "/"
@using GrpcGreeter
@inject Greeter.GreeterClient GreeterClient<h1>Invoke gRPC service</h1><p><input @bind="yourName" placeholder="Type your name" /><button @onclick="GetGreeting" class="btn btn-primary">Call gRPC service</button>
</p>Server response: <strong>@serverResponse</strong>@code {string yourName = "Bert";string serverResponse;async Task GetGreeting(){var request = new HelloRequest { Name = yourName };var reply = await GreeterClient.SayHelloAsync(request);serverResponse = reply.Message;}
}

现在在浏览器中尝试一下。用户界面看起来是这样的:

如果你查看浏览器开发者工具的 network 选项卡中的请求,你会看到它在发送和接收二进制protobuf消息:

总结和示例

现在你已经有了基础,如果你愿意,还可以进一步使用 gRPC 来进行服务器和客户机之间的所有数据交换。gRPC 工具将为你生成所有的数据传输类,提高网络流量的效率,并消除 url、HTTP 方法、状态代码和序列化等 HTTP-over-JSON 的问题。

还有一个更详细的示例(https://github.com/SteveSandersonMS/BlazorGrpcSamples/tree/master/Hosted),它是一个完整的 Blazor WebAssembly 托管应用程序,使用 gRPC 获取“天气预报”数据。如果你对从默认的基于json的解决方案升级到基于gRPC-Web的解决方案所需的具体步骤感兴趣,请参阅这个准确地显示了我所做的更改的差异对比(https://github.com/SteveSandersonMS/BlazorGrpcSamples/commit/72544c54085a35cd89aae20030d7f91d75317a2f)。

添加 gRPC 服务到一个独立部署的 Blazor WebAssembly 应用程序

如果你正在构建一个纯独立的 Blazor WebAssembly 应用程序,而不是托管在 ASP.NET Core,那么我们就不能对你将拥有什么样的服务器做任何假设(意思是你只开发客户端,而服务端是由别人开发的场景)。我们只能假设你要调用一些与 gRPC-Web 兼容的服务端点,它们可能是在其他主机上的 ASP.NET Core 服务上暴露,或者是一个在另一个 gRPC 服务周围的 Envoy gRPC-Web 包装器(https://blog.envoyproxy.io/envoy-and-grpc-web-a-fresh-new-alternative-to-rest-6504ce7eb880)。在这里我们唯一关心的是配置你的 Blazor WebAssembly 应用程序来使用它。设置客户端应用程序的大多数步骤与上面的“托管部署”情况相同。然而,在某些方面,它有点棘手,因为我们不能依赖于我们在“托管”情况下所做的一些假设。区别如下:

  • 获取和使用.proto文件

    假定你的外部 gRPC 服务维护者可以为你提供定义该服务的.proto文件。你可以将其复制到你的客户端项目中,并在.csproj中添加一个引用它的<Proto>项。为了让工具工作,你还需要添加类似这样的包引用:

      <!-- Needed temporarily until the next Blazor WebAssembly preview release --><PackageReference Include="Microsoft.AspNetCore.Blazor.Mono" Version="3.2.0-preview1.20052.1" /><!-- gRPC-Web packages --><PackageReference Include="Google.Protobuf" Version="3.11.2" /><PackageReference Include="Grpc.Net.Client" Version="2.27.0-dev202001100801" /><PackageReference Include="Grpc.Net.Client.Web" Version="2.27.0-dev202001100801" /><PackageReference Include="Grpc.Tools" Version="2.27.0-dev202001081219"><PrivateAssets>all</PrivateAssets><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets></PackageReference>
    
  • 配置客户端DI服务

    与“托管托管”情况类似,你将向Startup.cs中添加代码以添加gRPC-Web客户端服务。这里的主要区别是,你必须知道用于访问外部服务的 Base URL 是什么,因为我们不能再假设它的 Base URL 跟托管你的客户端应用程序的服务端的 Base URL 一样。因此,你的DI服务注册可能看起来更像以下内容:

    services.AddSingleton(services =>
    {
    #if DEBUGvar backendUrl = "https://localhost:5001"; // Local debug URL
    #elsevar backendUrl = "https://some.external.url:12345"; // Production URL
    #endif// Now we can instantiate gRPC clients for this channelvar httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()));var channel = GrpcChannel.ForAddress(backendUrl, new GrpcChannelOptions { HttpClient = httpClient });return new Greeter.GreeterClient(channel);
    });
    

    这将根据你是否在调试模式下构建而改变URL。

总结和示例

就是这样!现在,你的独立部署的 Blazor WebAssembly 应用程序可以使用外部的 gRPC-Web 服务。对于完整的可运行示例,下面是一个示例独立应用程序(https://github.com/SteveSandersonMS/BlazorGrpcSamples/tree/master/Standalone),它在外部 URL 上调用一个 gRPC-Web 服务。这个示例附带了一个实际的用于测试的 gRPC-Web 服务器,但是你可以分开考虑它。如果你想确切地看到我更改了什么,这里是与默认项目模板输出的差异(https://github.com/SteveSandersonMS/BlazorGrpcSamples/commit/d6ec609f2b7e6591958d38e4a207c9b4f52f0feb)。

你的反馈请求

如果你想进一步了解 gRPC,请查阅 ASP.NET Core gRPC 文档。请向我们提出你对 gRPC-Web 的意见和经验反馈,因为这将帮助我们选择如何以及是否在未来的 ASP.NET Core 版本中使 gRPC-Web 成 一个标准特性。你可以在这里发布评论,或者在 GitHub 上发布标题中带有“反馈”的 issue。

翻译自原文:https://blog.stevensanderson.com/2020/01/15/2020-01-15-grpc-web-in-blazor-webassembly

相关文章:

  • ASP.NET Core 现已支持gRPC-Web

  • .NET Core ❤ gRPC

  • 在 .NET Core 上 Code-first 方式实现 gRPC 

近期,观测分析平台 SkyWalking 的 .NET 自动探针 (SkyAPM-dotnet) 也已经支持了 grpc-dotnet 远程调用的链路跟踪采集,欢迎大家使用!如果喜欢,也请大家给点个星星!

项目地址:https://github.com/SkyAPM/SkyAPM-dotnet

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312160.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯2016初赛-生日蜡烛-枚举

题目描述 某君从某年开始每年都举办一次生日party&#xff0c;并且每次都要吹熄与年龄相同根数的蜡烛。 现在算起来&#xff0c;他一共吹熄了236根蜡烛。 请问&#xff0c;他从多少岁开始过生日party的&#xff1f; 输出 请填写他开始过生日party的年龄数。 代码如下&#…

【新书推荐】《ASP.NET Core微服务实战:在云环境中开发、测试和部署跨平台服务》 带你走近微服务开发...

《ASP.NET Core 微服务实战》译者序&#xff1a;https://blog.jijiechen.com/post/aspnetcore-microservices-preface-by-translator/“微服务”的概念在 2014 年正式提出之后&#xff0c;越来越多的团队开始用它来设计自己的业务系统&#xff0c;各种微服务框架和开发过程管理…

蓝桥杯2016初赛-有奖猜谜-模拟

题目描述 小明很喜欢猜谜语。最近&#xff0c;他被邀请参加了X星球的猜谜活动。 每位选手开始的时候都被发给777个电子币。 规则是&#xff1a;猜对了&#xff0c;手里的电子币数目翻倍&#xff0c;猜错了&#xff0c;扣除555个电子币, 扣完为止。 小明一共猜了15条谜语。战果…

linux6.5dns装什么,CentOS6.5安装DNS服务

1&#xff0c;安装软件包yum install -y bind2&#xff0c;备份配置文件cp /etc/named.conf /etc/named.conf_bak3&#xff0c;编辑配置文件vim /etc/named.conf//// named.conf//// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS// server as a c…

【在路上2】快递的运单轨迹

通达系早期的扫描数据高度类同&#xff0c;业务员从商家或散客收件之后&#xff0c;PDA做一次揽收操作。业务员或承包区把快件送到网点&#xff0c;晚上由网点派车统一送到转运中心&#xff0c;此时网点做一次发件扫描&#xff0c;转运中心做一次到件扫描。转运中心分拣后发出&…

蓝桥杯2017初赛-正则问题

题目描述 考虑一种简单的正则表达式&#xff1a;只由 x ( ) | 组成的正则表达式。 小明想求出这个正则表达式能接受的最长字符串的长度。 例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是&#xff1a; xxxxxx&#xff0c;长度是6 输入 输入一个由x()|组成的正则表达式。输入…

linux apache找不到woff2,使服务器Nginx(或者Apache)支持woff2等字体文件

为了在前端正确地显示字体&#xff0c;浏览器必须使用正确的http header来接受字体文件。如果服务器没有设置要求的头信息&#xff0c;那么有些浏览器就会在控制台报错或者直接不能显示。可能你的服务器已经配置好了&#xff0c;你无须再动任何东西。如果没有配置好&#xff0c…

.NET Core验证ASP.NET密码

.NET Core验证ASP.NET密码随着 .NETCore的持续更新和完善&#xff0c;越来越多的机构已经选择或者升级为 .NETCore。但由于技术不完全相同&#xff0c;不可能所有应用/数据库都能无缝迁移&#xff0c;因此 ASP.NETCore和传统 ASP.NET之间多少会存在一些挑战&#xff0c;需要更多…

蓝桥杯2017初赛-9数算式-dfs

题目描述 观察如下的算式&#xff1a;9213 x 85674 789314562 左边的乘数和被乘数正好用到了1~9的所有数字&#xff0c;每个1次。 而乘积恰好也是用到了1~9的所有数字&#xff0c;并且每个1次。 请你借助计算机的强大计算能力&#xff0c;找出满足如上要求的9数算式一共有多少…

linux下I2C驱动发送IO时序,I2C驱动情景分析——怎样控制I2C时序

内核版本&#xff1a;linux-3.4.2源程序&#xff1a; linux-3.4.2\drivers\i2c\busses\I2c-s3c2410.c这次要解决的问题是&#xff1a;如何配置soc的I2C模块&#xff0c;输出想要的时序波形&#xff1f;关于Linux里I2C驱动的架构&#xff0c;在转载的文章讲得相当透彻(《linu…

蓝桥杯2017初赛-分巧克力-二分

题目描述 **儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。 小明一共有N块巧克力&#xff0c;其中第i块是Hi x Wi的方格组成的长方形。 为了公平起见&#xff0c;小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足&#…

蓝桥杯2017初赛-外星日历-数论

题目描述 某星系深处发现了文明遗迹。他们的计数也是用十进制。 他们的文明也有日历。日历只有天数&#xff0c;没有年、月的概念。 有趣的是&#xff0c;他们也使用了类似“星期”的概念&#xff0c;只不过他们的一个星期包含了9天&#xff0c;为了方便&#xff0c;这里分别记…

ubuntu14.04安装linux公社,Ubuntu 14.04下安装IT++

Ubuntu 14.04 下安装 IT(itpp)(官方二进制包安装版)温馨提示&#xff1a;虽然没有尝试&#xff0c;不过直接运行最后一步应该也可以成功。另外&#xff0c;既然有简单的方法&#xff0c;不到破不得以还是不要尝试麻烦的方法了。1、安装 FFTW3sudo apt-get install libfftw3-dev…

.NET CORE(C#) WPF 值得推荐的动画菜单设计

微信公众号&#xff1a;Dotnet9&#xff0c;网站&#xff1a;Dotnet9&#xff0c;问题或建议&#xff1a;请网站留言&#xff0c; 如果对您有所帮助&#xff1a;欢迎赞赏。.NET CORE(C#) WPF 值得推荐的动画菜单设计阅读导航本文背景代码实现本文参考源码1. 本文背景YouTube上老…

蓝桥杯2017初赛-k倍区间-前缀和

题目描述 给定一个长度为N的数列&#xff0c;A1, A2, … AN。 如果其中一段连续的子序列Ai, Ai1, … Aj(i < j)之和是K的倍数&#xff0c;我们就称这个区间[i, j]是K倍区间。 你能求出数列中总共有多少个K倍区间吗&#xff1f; 输入 第一行包含两个整数N和K。(1 < N, K …

【在路上3】大数据离线分析快递的派件时效

【在路上1】快递物流大数据的由来【在路上2】快递的运单轨迹几乎人人都用过快递&#xff0c;如果说用户最在意什么&#xff1f;那必然是谁家送得快&#xff01;这也是整个快递物流行业被诟病最多的地方。都知道顺丰送得快&#xff0c;但价格摆在那里&#xff0c;且它的市场份额…

c语言学生成绩查询课设报告,C语言课设报告(学生考试成绩查询程序)【荐】.doc...

C语言课设报告(学生考试成绩查询程序)【荐】.doc学生考试成绩查询程序学号&#xff1a;********姓名&#xff1a;*****完成日期&#xff1a;****年月通过键盘输入学生的考试信息&#xff0c;包括&#xff1a;学号、姓名、课程名称、学分、考试分数(一个学生应考数门课程&#x…

DevExpress作为企业赞助商加入.NET基金会

.NET基金会是一个独立的非营利组织&#xff0c;于2014年成立&#xff0c;旨在围绕 .NET 不断增长的开源技术集合&#xff0c;促进开放开发和协作。它是商业和社区开发人员的论坛&#xff0c;通过促进开放性&#xff0c;社区参与和快速创新来增强.NET生态系统的未来。要使.NET 基…

蓝桥杯第四届初赛-买不到的数目-数论

题目描述 小明开了一家糖果店。他别出心裁&#xff1a;把水果糖包成4颗一包和7颗一包的两种。糖果不能拆包卖。 小朋友来买糖的时候&#xff0c;他就用这两种包装来组合。当然有些糖果数目是无法组合出来的&#xff0c;比如要买 10 颗糖。 你可以用计算机测试一下&#xff0c;…

【在路上4】在派件时效分析中剥离有效因素

昨天提到&#xff0c;即使有了末端派件时效的初步分析&#xff0c;也免不了各种各样数之不尽的主观客观因素&#xff0c;以至于进入困境。此时此刻&#xff0c;让我们重头再来&#xff0c;这个项目的核心目标是什么&#xff1f;---找到末端派件效率底下的关键点&#xff0c;并给…