前言

在上两篇文章中,介绍了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学习实验004:Elasticsearch的简单介绍和操作

    一 集群节点 Elstaicsearch的集群是由多个节点组成都,通过cluster.name设置集权名称,比能切用与区分其他的集群,每个节点通过node.name指定节点 在Elasticsearc ...

  2. Python 多态与抽象类

    一.多态 1.1 什么是多态 多态也称"多态性",指的是同一种类型的事物,不同的形态. 在python中的多态指的是让多种类若具备类似的数据属性与方法属性,都统一好命名规范,这样可 ...

  3. CSP201803-4棋局评估

    问题描述 Alice和Bob正在玩井字棋游戏. 井字棋游戏的规则很简单:两人轮流往3*3的棋盘中放棋子,Alice放的是“X”,Bob放的是“O”,Alice执先.当同一种棋子占据一行.一列或一条对角 ...

  4. 【小技巧】在PS中测量图层间的边距

    今天学到了一个小技巧,前端切页面时会很方便,就是测量间距margin的. 在ps中,选中某个图层,然后按住ctrl键,再移动鼠标,就可以出现这个图层距其他元素的边距,这个太方便了.在此记录一下,免的以 ...

  5. 斜率优化入门题题单$QwQ$

    其实就是这一篇的那个例题帕的大部分题目的题解就写这儿辣,,, 因为都是些基础题不想专门给写题解,,,但是又掌握得差不得不写,,, 麻油办法就写一块儿好辣$QwQ$ 当然辣比较难的我就没放进来辣$QwQ ...

  6. 大数据学习之路-hdfs

    1.什么是hadoop hadoop中有3个核心组件: 分布式文件系统:HDFS —— 实现将文件分布式存储在很多的服务器上 分布式运算编程框架:MAPREDUCE —— 实现在很多机器上分布式并行运 ...

  7. c语言中自定义bool类型模板

    首先,c语言中没有bool类型,只有c++中有,所以需要自定义,即c中表示bool类型的方法: 1.模板1 typedef int bool; #define false 0 #define true ...

  8. PHP 经典面试题集

    这篇文章介绍的内容是关于PHP 经典面试题集 PHP 经典面试题集,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 结合我自己面试情况,面对的一些php面试题列举出来,基本上结合自己的看 ...

  9. 阿里云ECS服务器Ubuntu配置MySQL远程访问

    root账户登录服务器Ubuntu16.04 apt-get update apt-get install mysql-server mysql-client; 安装时会让你设置root密码,输入2次 ...

  10. [ASP.NET Core 3框架揭秘] Options[2]: 配置选项的正确使用方式[下篇]

    四.直接初始化Options对象 前面演示的几个实例具有一个共同的特征,即都采用配置系统来提供绑定Options对象的原始数据,实际上,Options框架具有一个完全独立的模型,可以称为Options ...