.NetCore|.Net6 gRPC服务开发及本地调试
前言
最近在项目中实装应用了gRPC技术,本着能把技术描述出来给别人能看的懂的思想及作为自己学习笔记的心态编写了此文。因为在实际项目中是webApi接口和gRPC接口使用在同一项目服务中,所以本文的例子也是建立在webApi项目而非控制台项目中。
1、gRPC介绍
gRPC 是Google发起的一个开源远程过程调用 系统。该系统基于HTTP/2 协议传输,使用Protocol Buffers 作为接口描述语言。 其他功能: 认证 双向流 流控制 超时 最常见的应用场景是: 微服务框架下,多种语言服务之间的高效交互。 将手机服务、浏览器连接至后台 产生高效的客户端库-- 维基百科
微软官网介绍:
gRPC是一种与语言无关的高性能远程过程调用 (RPC) 框架。
gRPC 的主要好处是:
现代、高性能、轻量级的 RPC 框架。
合约优先的 API 开发,默认使用 Protocol Buffers,允许语言无关的实现。
可用于多种语言的工具来生成强类型服务器和客户端。
支持客户端、服务器和双向流式调用。
通过 Protobuf 二进制序列化减少网络使用。
这些优势使 gRPC 非常适合:
效率至关重要的轻量级微服务。
需要多种语言进行开发的多语言系统。
需要处理流请求或响应的点对点实时服务。
2、gRPC服务端开发
服务端的接口以传入一个组织id作为入参,返回该组织用户基本信息为例子
* 首先创建一个webApi项目作为服务端

程序包管理器控制台添加 Grpc.AspNetCore nuget包引用
Install-Package Grpc.AspNetCore -Version 2.47.0
*新建一个Grpc及Proto文件夹分别放置 gRPC服务和proto文件(方便管理)
在proto文件夹下新建一个 user.proto 文件(vs 文件模板没有该后缀名文件,直接新建任意文件改文件名即可),在 user.proto文件中定义gRPC服务方法、入参及返回值
点击查看代码
syntax = "proto3";
option csharp_namespace = "GrpcUser";
package UserApi;
service User {
rpc GetUserByOrganizationId(OrganizationUserRequest) returns (OrganizationUserRequestResponse) {}
}
message OrganizationUserRequest {
string organizationid = 1;
}
message OrganizationUserRequestResponse {
string organizationid = 1;
repeated OrganizationUserItemResponse items = 2;
}
message OrganizationUserItemResponse {
string id = 1;
string name =2;
int32 sex = 3;
}
- 右键编辑项目文件,增加一个节点,并把 user.proto 文件包含进去
点击查看代码
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
<ItemGroup>
<Folder Include="Grpc\" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="Proto\user.proto" GrpcServices="Server" Generator="MSBuild:Compile"/>
</ItemGroup>
</Project>
- Grpc文件夹下新建类 UserService,并继承 User.UserBase 并重写 GetUserByOrganizationId 方法实现并接口业务
点击查看代码
using Grpc.Core;
using GrpcUser;
namespace gRPCServer.Grpc
{
public class UserService : User.UserBase
{
public override Task<OrganizationUserResponse> GetUserByOrganizationId(OrganizationUserRequest request, ServerCallContext context)
{
/*******此处实际业务从持久层获取数据**********/
var organizationUser = new OrganizationUser(request.Organizationid);
organizationUser.Items = GetUserInfos();
return Task.FromResult(MapToResponse(organizationUser));
}
private List<UserInfo> GetUserInfos()
{
var userInfos = new List<UserInfo>();
userInfos.Add(new UserInfo
{
Id = 1,
Name = "用户1",
Sex = 0
});
userInfos.Add(new UserInfo
{
Id = 2,
Name = "用户2",
Sex = 1
});
return userInfos;
}
private OrganizationUserResponse MapToResponse(OrganizationUser organizationUser)
{
var response = new OrganizationUserResponse()
{
Organizationid = organizationUser.OrganizationId
};
organizationUser.Items.ForEach(item => response.Items.Add(new OrganizationUserItemResponse
{
Id = item.Id,
Name = item.Name,
Sex = item.Sex
}));
return response;
}
}
public class OrganizationUser
{
public string? OrganizationId { get; set; }
public List<UserInfo> Items { get; set; }
public OrganizationUser(string organizationId)
{
OrganizationId = organizationId;
}
}
public class UserInfo
{
public int Id { get; set; }
public string Name { get; set; }
public int Sex { get; set; }
}
}
- 在Program 文件中启用grpc中间件并映射我们写好的服务
//启用grpc
builder.Services.AddGrpc();
//映射grpc服务
app.MapGrpcService<UserService>();
- 因为我们的项目是跑在webApi的项目中,所以还要配置内核去监听另一个端口才能接收并处理gRPC的请求
builder.WebHost.ConfigureKestrel(
options =>
{
//webApi监听端口
options.Listen(System.Net.IPAddress.Any, 5157, listenOptions =>
{
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2;
});
//grpc监听端口
options.Listen(System.Net.IPAddress.Any, 5158, listenOptions =>
{
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2;
});
}
);
- 完整的Program
点击查看代码
using gRPCServer.Grpc;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(
options =>
{
//webApi监听端口
options.Listen(System.Net.IPAddress.Any, 5157, listenOptions =>
{
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2;
});
//grpc监听端口
options.Listen(System.Net.IPAddress.Any, 5158, listenOptions =>
{
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2;
});
}
);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//启用grpc
builder.Services.AddGrpc();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
//映射grpc服务
app.MapGrpcService<UserService>();
app.UseAuthorization();
app.MapControllers();
app.Run();
- 这样,我们的gRPC的服务端就搞定了,完整的项目结构就变成这样了
3、gRPC客户端开发
客户端项目我们也是新建一个webApi项目,并在webapi接口中调用我们的gRPC服务接口获取数据并以json格式输出
* 首先新建一个webApi项目
- 程序包管理器控制台添加 Grpc.AspNetCore nuget包引用
Install-Package Grpc.AspNetCore -Version 2.47.0
- 新建文件夹proto,并将 gRPCServer项目的 user.proto 文件拷贝过来
- 右键编辑项目文件,增加一个节点,并把 user.proto 文件包含进去(节点Server属性要设置为 Client)
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers\" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="Proto\user.proto" GrpcServices="Client" Generator="MSBuild:Compile"/>
</ItemGroup>
</Project>
- 在Program文件中注入 Grpc客户端
//注入grpc客户端
builder.Services.AddGrpcClient<GrpcUser.User.UserClient>(
options =>
{
options.Address = new Uri("http://localhost:5158"); //grpcServer项目配置的grpc服务监听端口
});
- 新建控制器 UserController 调用 grpcClient获取数据
using Microsoft.AspNetCore.Mvc;
using GrpcUser;
namespace gRPCClient.Controllers
{
[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
private User.UserClient _userClient;
public UserController(User.UserClient userClient)
{
_userClient = userClient;
}
/// <summary>
/// 获取用户
/// </summary>
/// <param name="organizationId"></param>
/// <returns></returns>
[HttpGet]
public async Task<OrganizationUserResponse> GetUser(string organizationId)
{
var user = await _userClient.GetUserByOrganizationIdAsync(new OrganizationUserRequest { Organizationid = organizationId });
return user;
}
}
}
先启动 grpcSever项目,然后再启动 client项目,在swagger页面调用 GetUser方法即可获取到grpc接口返回数据,Grpc服务于客户端调用就搭建好了
完整项目结构
4、gRPC服务端接口本地调试
grpcServer的接口服务不能像webApi一样直接启动就能进行调试,需要借助一些第三方中间件进行协助测试。我这边使用的是grpcui 进行对本地grpc服务接口的开发调试,下面是grpcui的安装及使用步骤
grpcui是Go语言编写的,所以第一步我们先要进行Go环境的搭建。
打开Go官网 ,下载并安装
安装完成,以管理员身份打开PowerShell,并修改Go环境变量
go env -w GO111MODULE=on
因为Go 包源在外网,所以我们要设置一些代理,方便安装
go env -w GOPROXY=https://goproxy.cn,direct
安装grpcui
go install github.com/fullstorydev/grpcui/cmd/grpcui@latest
安装完成即可使用命令测试是否安装成功
grpcui --help
安装完调试工具还需要修改一些我们的grpcService项目,让项目把grpc服务接口给反射出来,grpcui工具才能获取到相应接口并以webUi的方式进行调试
程序包管理器控制台添加 Grpc.AspNetCore.Server.Reflection nuget包引用
Install-Package Grpc.AspNetCore.Server.Reflection -Version 2.47.0
项目注入grpc服务反射包服务
builder.Services.AddGrpcReflection();
启用grpc映射
app.MapGrpcReflectionService();
最终gRPCServer项目的Program 文件配置如下
using gRPCServer.Grpc;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(
options =>
{
//webApi监听端口
options.Listen(System.Net.IPAddress.Any, 5157, listenOptions =>
{
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2;
});
//grpc监听端口
options.Listen(System.Net.IPAddress.Any, 5158, listenOptions =>
{
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2;
});
}
);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//启用grpc
builder.Services.AddGrpc();
//启用grpc反射
builder.Services.AddGrpcReflection();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
//映射grpc服务
app.MapGrpcService<UserService>();
//映射grpc反射服务
app.MapGrpcReflectionService();
app.UseAuthorization();
app.MapControllers();
app.Run();
启动gRPC项目
PowerShell 执行命令
grpcui -plaintext {grpc服务的ip端口地址}
即可开启webUi界面调试grpc接口
启动的WebUI调试页面
在此页面我们就可以像使用Postman调试webApi一样调试我们的grpc接口了
参考资料:
微软gRPC使用教程:https://docs.microsoft.com/en-us/aspnet/core/grpc/?view=aspnetcore-6.0
grpcui测试grpc服务教程:https://docs.microsoft.com/en-us/aspnet/core/grpc/test-tools?view=aspnetcore-6.0
grpcui项目教程:https://github.com/fullstorydev/grpcui
.NetCore|.Net6 gRPC服务开发及本地调试的更多相关文章
- 微信公众号开发 VS2015本地调试
1.部署一个微信公众号服务在本地IIS: 2.下载一个ngrok 穿网工具,放到部署文件夹根目录: ngrok穿网 在部署路径下打开cmd,输入 ngrok http [端口号] 4.将映射的URL ...
- 利用NATAPP隧道解决微信公众号开发之本地调试难题
一.问题 众所周知,微信公众号开发需要公网的有效域名和80端口,本机当然互联网是访问不了的.那么我们难道去一个公网的服务器去开发吗?那样是不是太土了. 答案当然是,NO 当然我们在做微信支付的时候,有 ...
- ballerina 学习二十八 快速grpc 服务开发
ballerina 的grpc 开发模型,对于开发者来说简单了好多,不是schema first 的方式,而是我们 只要编写简单的ballerina service 就可以了,proto 文件是自动帮 ...
- C# Windows Service服务的创建和调试
前言 关于Windows服务创建和调试的文章在网络上的很多文章里面都有,直接拿过来贴在这里也不过仅仅是个记录,不会让人加深印象.所以本着能够更深刻了解服务项目的创建和调试过程及方法的目的,有了这篇记录 ...
- chrome本地调试跨域问题
1.关闭chrome浏览器(全部) 我们可以通过使用chrome命令行启动参数来改变chrome浏览器的设置,具体的启动参数说明参考这篇介绍.https://code.google.com/p/xia ...
- 五分钟给你的 gRPC服务 加上 HTTP 接口
gRPC 服务要加 HTTP 接口? go-zero 给大家带来极简的 RESTful 和 gRPC 服务开发体验的同时,社区又给我们提出了新的期望: 我想只写一次代码 既要 gRPC 接口 也要 H ...
- 【.NET6】gRPC服务端和客户端开发案例,以及minimal API服务、gRPC服务和传统webapi服务的访问效率大对决
前言:随着.Net6的发布,Minimal API成了当下受人追捧的角儿.而这之前,程序之间通信效率的王者也许可以算得上是gRPC了.那么以下咱们先通过开发一个gRPC服务的教程,然后顺势而为,再接着 ...
- Adnc如何本地调试 - 一个轻量级的.Net Core微服务开发框架
前言 Adnc是一个轻量级的.Net Core微服务开发框架,同样适用于单体架构系统的开发. 如果只是想本地调试,只需要安装必备软件,必备软件除开发工具外,其它软件建议大家都使用`do ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十四)——开发环境容器调试小技巧
之前有很多同学提到如何做容器调试,特别是k8s环境下的容器调试,今天就讲讲我是如何调试的.大家都知道在vs自带的创建项目模板里勾选docker即可通过F5启动docker容器调试.但是对于启动在k8s ...
随机推荐
- XCTF练习题---MISC---Training-Stegano-1
XCTF练习题---MISC---Training-Stegano-1 flag:steganoI 解题步骤: 1.观察题目,下载附件 2.打开下载的图片文件,发现就是一个点,修改文件扩展名,还是说查 ...
- Blazor和Vue对比学习(基础1.2):模板语法和Razor语法
Vue使用模板语法,Blazor使用祖传的Razor语法,从逻辑和方向上看,两者极为相似,比如: 都基于HTML 都通过声明式地将组件实例的状态(数据/方法)绑定到呈现的DOM上 都通过指令实现更加丰 ...
- 【python疫情可视化】用pyecharts开发全国疫情动态地图,效果酷炫!
一.效果演示 我用python开发了一个动态疫情地图,首先看下效果: 如图所示,地图根据实时数据通过时间线轮播的方式,动态展示数据的变化.随着时间的推移,疫情确诊数量的增多,地图各个省份颜色逐渐加深, ...
- Wireshark抓包分析TCP“三次握手,四次挥手”
1.目的 客户端与服务器之间建立TCP/IP连接,我们知道是通过三次握手,四次挥手实现的,但是很多地方对这个知识的描述仅限于理论层面,这次我们通过网络抓包的方式来看一下实际的TCP/IP传输过程. 2 ...
- 函数式接口和@FunctionalInterface
函数式接口的特点 接口有且仅有一个抽象方法 允许定义静态方法和默认方法(这两个都不是抽象方法) 允许java.lang.Object中的public方法(因为任何一个函数式接口的实现,默认都继承了Ob ...
- mysql Bad handshake
由于 Java 程序访问 MySQL 时,MySQL 抛出 Bad handshake 错误,导致接口抛错,然后在 MySQL 配置文件新增 skip_ssl 配置(忽略 SSL 密钥和证书文件),重 ...
- JS作用域与闭包
JS作用域与闭包 在JavaScript中,作用域是可访问变量,对象,函数的集合. 变量分为全局变量和局部变量.全局变量在函数外定义,HTML中全局变量是window对象,所有数据对象都属于windo ...
- Linux下将一个文件压缩分包成多个小文件
压缩分包 将文件test分包压缩成10M 的文件: tar czf - test | split -b 10m - test.tar.gz 解压 将第一步分拆的多个包解压: cat test.tar. ...
- 项目中导入本地jar包问题
1. 问题 一个Maven项目,需要依赖一个本地jar包,以如下方式引用: <dependency> <groupId>xxx.sdk</groupId> < ...
- 「Java分享客栈」随时用随时翻:微服务链路追踪之zipkin搭建
前言 微服务治理方案中,链路追踪是必修课,SpringCloud的组件其实使用很简单,生产环境中真正令人头疼的往往是软件维护,接口在微服务间的调用究竟哪个环节出现了问题,哪个环节耗时较长,这都是项目上 ...