.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---Ditf
XCTF练习题---MISC---Ditf flag:flag{Oz_4nd_Hir0_lov3_For3ver} 解题步骤: 1.观察题目,下载附件 2.这道题是安恒办的一场比赛题目,下载附件以后是 ...
- LintCode-165 · 合并两个排序链表-题解
描述:将两个排序(升序)链表合并为一个新的升序排序链表样例 1:输入: list1 = null, list2 = 0->3->3->null输出: 0->3->3-&g ...
- springboot:使用异步注解@Async的前世今生
在前边的文章中,和小伙伴一起认识了异步执行的好处,以及如何进行异步开发,对,就是使用@Async注解,在使用异步注解@Async的过程中也存在一些坑,不过通过正确的打开方式也可以很好的避免,今天想和大 ...
- 关于win10安装wsl子系统Ubuntu图形界面的错误解决
解决了https://blog.csdn.net/weixin_30834783/article/details/102144314Xserver个人使用的是VcXsrv. 在WSL中配置环境变量DI ...
- 聊一聊 HBase 是如何写入数据的?
hi,大家好,我是大D.今天继续了解下 HBase 是如何写入数据的,然后再讲解一下一个比较经典的面试题. Region Server 寻址 HBase Client 访问 ZooKeeper: 获取 ...
- layui数据表格搜索
简单介绍 我是通过Servlet传递json给layui数据表格模块,实现遍历操作的,不过数据量大的话还是需要搜索功能的.这是我参考网上大佬代码写出的搜索功能. 实现原理 要实现搜索功能,肯定需要链接 ...
- 从零搭建react+ts组件库(封装antd)
为什么会有这样一篇文章?因为网上的教程/示例只说了怎么做,没有系统详细的介绍引入这些依赖.为什么要这样配置,甚至有些文章还是错的!迫于技术洁癖,我希望更多的开发小伙伴能够真正的理解一个项目搭建各个方面 ...
- 官方出品,比 mydumper 更快的逻辑备份工具
mysqldump 和 mydumper 是我们常用的两个逻辑备份工具. 无论是 mysqldump 还是 mydumper 都是将备份数据通过 INSERT 的方式写入到备份文件中. 恢复时,myl ...
- Linux下添加MySql组件后报无权限问题解决
Tomcat日志报错如下: Caused by: java.sql.SQLException: Access denied for user 'root'@'localhost' (using pas ...
- 队列的java实现
今天老师提出一个问题,就是如何用java实现队列呢?我在网上找了许多资料,发现java也是可以很轻松的实现队列. 如下代码: package com; import java.util.Collect ...