前言

在上两篇文章中,介绍了ASP.NET Core 中的 gRPC-Web 实现在 Blazor WebAssembly 中使用 gRPC-Web,实现了 Blazor WebAssembly 调用 ASP.NET Core gRPC-Web。虽然 ASP.NET Core 中的 gRPC-Web 实现目前还是试验性项目,但是鉴于它在生态上的重大意义,说不定我们很快就能在正式版本中使用。

虽然 Blazor WebAssembly 现在已经是 .NET 进军前端的大热门,但有同学说,只介绍了 Blazor WebAssembly 的调用方法还不够呀,现在比较常用的还是 JS/TS 前端,那么本篇,我就介绍一下在前端 JS/TS 中调用 ASP.NET Core gRPC-Web。

其实 gRPC-Web 项目本身,就是为 JS/TS 提供 gRPC 能力的,让不支持 HTTP/2 的客户端和服务端也能使用 gRPC 的大部分特性。gRPC-Web 项目提供了一个 protoc CLI 插件,可用于把 proto 协议文件转换为 JS/TS 语言可导入的对应 gRPC 服务的客户端,还生成了 .d.ts 文件来支持 Typescript。

示例

接下来,我就来展示一下,用 Visual Studio 自带的 ASP.NET Core + Angular 模板创建的项目,把原来的 WebApi 调用改造成 gRPC-Web 调用。

本示例基于 .NET Core 3.1,请安装好最新的 .NET Core SDK 和 Visual Studio 2019。

创建项目

打开 Visual Studio 2019,创建新项目 -> 选择"ASP.NET Core Web 应用程序" -> 填写项目名 -> 选择 "Angular" 项目模板。如图:

我们就是用这个项目,把 fetch-data 页面获取数据的方式修改为 gRPC-Web 。

添加 gRPC proto 文件

在项目中新建一个目录 Protos,创建文件 weather.proto :

syntax = "proto3";

import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto"; option csharp_namespace = "AspNetCoreGrpcWeb"; package WeatherForecast; service WeatherForecasts {
rpc GetWeather (google.protobuf.Empty) returns (WeatherReply);
} message WeatherReply {
repeated WeatherForecast forecasts = 1;
} message WeatherForecast {
google.protobuf.Timestamp dateTimeStamp = 1;
int32 temperatureC = 2;
int32 TemperatureF = 3;
string summary = 4;
}

可以看到 proto 中导入了官方库的其他 proto 文件,它们是编译用的辅助文件。对于.NET Core 项目,可以通过引用 Google.Protobuf 这个包引入。

修改 ASP.NET Core 服务端

我们先修改服务端,让 ASP.NET Core 提供 gRPC-Web 服务。

由于 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" />
</packageSources>
</configuration>

再添加必要的 Nuget 包引用:

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

接着,修改原来的 WeatherForecastController 改为 WeatherForecastService:

    public class WeatherForecastsService : WeatherForecasts.WeatherForecastsBase
{
private static readonly string[] Summaries = {
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
}; public override Task<WeatherReply> GetWeather(Empty request, ServerCallContext context)
{
var reply = new WeatherReply(); var rng = new Random();
reply.Forecasts.Add(Enumerable.Range(1, 5).Select(index =>
{
var temperatureC = rng.Next(-20, 55);
return new WeatherForecast
{
DateTimeStamp = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(index)),
TemperatureC = temperatureC,
TemperatureF = 32 + (int)(temperatureC / 0.5556),
Summary = Summaries[rng.Next(Summaries.Length)]
};
})); return Task.FromResult(reply);
}
}

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

  services.AddGrpc();

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

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

  app.UseGrpcWeb();

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

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

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

修改 Angular 项目

项目的 ClientApp 目录中,就是 Angular 的项目文件,使用 ASP.NET Core 托管,是这个项目模板约定的。

我们需要先通过 proto 生成需要的 js 文件。

安装 npm 包

运行命令:

 npm i protoc google-protobuf ts-protoc-gen @improbable-eng/grpc-web -s

生成 js 文件

在 ClientApp 目录下创建目录 proto ,再运行命令:

./node_modules/protoc/protoc/bin/protoc --plugin="protoc-gen-ts=.\node_modules\.bin\protoc-gen-ts.cmd" --js_out="import_style=commonjs,binary:./../Protos" --ts_out="service=grpc-web:src/app/proto" -I ./../Protos ../Protos/*.proto

可以在proto目录中看到生成了 4 个文件(每个 proto 会生成 4 个)

  • weather_pb_service.js: 包含了 rpc 调用客户端 WeatherForecastsClient
  • weather_pb.js: 包含了传输对象 WeatherForecast。这个文件在原 proto 的目录下,需要手动移过来。
  • 两个 *.d.ts 文件是对应以上两个文件的类型描述,用于 TS。

修改 fetch-data 页面组件

接下来,需要引用生成的文件,创建一个 WeatherForecastsClient 来调用 gRPC-Web 服务端。

  • fetch-data.component.ts

    import { Component } from '@angular/core';
    import { WeatherForecast } from '../proto/weather_pb';
    import { WeatherForecastsClient } from '../proto/weather_pb_service';
    import { Empty } from 'google-protobuf/google/protobuf/empty_pb'; @Component({
    selector: 'app-fetch-data',
    templateUrl: './fetch-data.component.html',
    })
    export class FetchDataComponent {
    public forecasts: WeatherForecast[]; private client: WeatherForecastsClient;
    constructor() {
    this.client = new WeatherForecastsClient('https://localhost:5001');
    this.client.getWeather(new Empty(), (error, reply) => {
    if (error) {
    console.error(error);
    } this.forecasts = reply.getForecastsList();
    });
    }
    }
  • fetch-data.component.html

    <h1 id="tableLabel">Weather forecast</h1>
    
    <p>This component demonstrates fetching data from the server.</p>
    
    <p *ngIf="!forecasts"><em>Loading...</em></p>
    
    <table class="table table-striped" aria-labelledby="tableLabel" *ngIf="forecasts">
    <thead>
    <tr>
    <th>Date</th>
    <th>Temp. (C)</th>
    <th>Temp. (F)</th>
    <th>Summary</th>
    </tr>
    </thead>
    <tbody>
    <tr *ngFor="let forecast of forecasts">
    <td>{{ forecast.getDatetimestamp().toDate() }}</td>
    <td>{{ forecast.getTemperaturec() }}</td>
    <td>{{ forecast.getTemperaturef() }}</td>
    <td>{{ forecast.getSummary() }}</td>
    </tr>
    </tbody>
    </table>

可以看到:

  • 创建 WeatherForecastsClient 对象需要传入服务端的 HostName,要注意不要用 /后缀。
  • 生成出来的 WeatherForecast 类型包含getter/setter, 而 WeatherForecast.AsObject 类才是值对象,可以直接访问属性值,需要调用 .toObject() 方法进行转换。
  • datetimestamp 属性的类型 proto.google.protobuf.Timestamp 是 protobuf 里的关键字,调用 toDate() 方法可转换为 TS 的 Date 类型。

运行项目

完事具备,我们可以运行项目了。访问 https://localhost:5001/fetch-data,就可以看到前端是通过 gRPC-Web 获取数据了。

总结

可以看出,要在前端 JS/TS 使用 gRPC-Web 虽然在开发工具上没有 Blazor WebAssembly 方便,但是从 proto 生成客户端之后,前端的 TS 代码就能直接获得强类型的调用方法和路由,很简单地得到 gRPC 带来的好处。另外,gRPC-Web 项目本身已经 GA,所以我们可以先在后端使用它的 gRPC 代理,而前端可以放心大胆地在我们的生产项目中使用它。等到 ASP.NET Core 正式支持 gRPC-Web 后,就可以不需要代理了,比其他平台和语言都更有优势。

本示例的源码已发布到 Github:https://github.com/ElderJames/AspNetCoreGrpcWeb

前端 JS/TS 调用 ASP.NET Core gRPC-Web的更多相关文章

  1. ASP.NET Core gRPC 入门全家桶

    一. 说明 本全家桶现在只包含了入门级别的资料,实战资料更新中. 二.官方文档 gRPC in Asp.Net Core :官方文档 gRPC 官网:点我跳转 三.入门全家桶 正片: ASP.NET ...

  2. 旧 WCF 项目迁移到 asp.net core + gRPC 的尝试

    一个月前,公司的运行WCF的windows服务器down掉了,由于 AWS 没有通知,没有能第一时间发现问题. 所以,客户提出将WCF服务由C#改为JAVA,在Linux上面运行:一方面,AWS对Li ...

  3. ASP.NET Core GRPC 和 Dubbo 互通

    一.前言 Dubbo 是比较流行的服务治理框架,国内不少大厂都在使用.以前的 Dubbo 使用的是私有协议,采集用的 hessian 序列化,对于多语言生态来说是极度的不友好.现在 Dubbo 发布了 ...

  4. 将前端js异步调用的多个服务合并为一个前端服务

    将前端js异步调用的多个服务合并为一个前端服务 1. 减少前端js异步请求的次数改善浏览体验 2. 方便地针对单个接口做异常降级处理

  5. ASP.NET Core gRPC 健康检查的实现方式

    一. 前言 gRPC 服务实现健康检查有两种方式,前面在此文 ASP.NET Core gRPC 使用 Consul 服务注册发现 中有提到过,这里归纳整理一下.gRPC 的健康检查,官方是定义了标准 ...

  6. angular4和asp.net core 2 web api

    angular4和asp.net core 2 web api 这是一篇学习笔记. angular 5 正式版都快出了, 不过主要是性能升级. 我认为angular 4还是很适合企业的, 就像.net ...

  7. 温故知新,使用ASP.NET Core创建Web API,永远第一次

    ASP.NET Core简介 ASP.NET Core是一个跨平台的高性能开源框架,用于生成启用云且连接Internet的新式应用. 使用ASP.NET Core,您可以: 生成Web应用和服务.物联 ...

  8. Dapr 运用之集成 Asp.Net Core Grpc 调用篇

    前置条件: <Dapr 运用> 改造 ProductService 以提供 gRPC 服务 从 NuGet 或程序包管理控制台安装 gRPC 服务必须的包 Grpc.AspNetCore ...

  9. ASP.NET Core gRPC 使用 Consul 服务注册发现

    一. 前言 gRPC 在当前最常见的应用就是在微服务场景中,所以不可避免的会有服务注册与发现问题,我们使用gRPC实现的服务可以使用 Consul 或者 etcd 作为服务注册与发现中心,本文主要介绍 ...

随机推荐

  1. ELK学习实验009:安装kibana的仪表盘

    一 metricbeat仪表盘 1.1 安装metricbeat仪表盘 可以将metricbeat数据在kibana中展示 [root@node4 ~]# cd /usr/local/metricbe ...

  2. Analysis of Two-Channel Generalized Sidelobe Canceller (GSC) With Post-Filtering

    作者:凌逆战 地址:https://www.cnblogs.com/LXP-Never/p/12071748.html 题目:带后置滤波的双通道广义旁瓣相消器(GSC)的分析 作者:Israel Co ...

  3. 从零开始のcocos2dx生活(五)ActionEase

    文章目录 sineEaseIn sineEaseOut sineEaseInOut expoEaseIn expoEaseOut expoEaseInOut easeIn easeOut easeIn ...

  4. “Deep models under the GAN: information leakage from collaborative deep learning”阅读笔记

    一.摘要 指出深度学习在机器学习场景下的优势,以及深度学习快速崛起的原因.随后点出研究者对于深度学习隐私问题的考虑.作者提出了一种强力的攻击方法,在其攻击下任何分布式.联邦式.或者中心化的深度学习方法 ...

  5. ScheduledThreadPoolExecutor中定时周期任务的实现源码分析

    ScheduledThreadPoolExecutor是一个定时任务线程池,相比于ThreadPoolExecutor最大的不同在于其阻塞队列的实现 首先看一下其构造方法: public Schedu ...

  6. 带有外部Tomcat的Spring Boot

    在本文中,我将如何在外部Tomcat上运行Spring Boot应用程序.对我来说,这是一个现实的场景,我必须解决这个问题,因此也请教了一下优锐课老师,得到了很多帮助.也希望当你遇到类似问题时,能为你 ...

  7. 利用cuteftp上传并修改网站上内容

    1.下载cuteftp 2.在host中输入网址(如:219.142.121.2) 3.username中输入(如:BNULS) 4.passpord中输入:(如410teamgood) 5.端口输入 ...

  8. Jmeter+Jenkins 搭配进行接口测试

    单纯通过Jmeter的界面进行Web的接口测试,效率低下.为此将Jmeter的接口测试与Jenkins联合,实现持续集成.配置完成后,只需修改运行的Jmeter脚本即可,运行结束后测试结果发送到指定邮 ...

  9. 从头学pytorch(十八):GoogLeNet

    GoogLeNet GoogLeNet和vgg分别是2014的ImageNet挑战赛的冠亚军.GoogLeNet则做了更加大胆的网络结构尝试,虽然深度只有22层,但大小却比AlexNet和VGG小很多 ...

  10. docker制作cenos+php56+nginx镜像

    首先你环境要安装好docker 1 获取centos镜像. docker search centos 选取第一个官方镜像. docker pull  docker.io/centos 新建镜像挂载目录 ...