8

.NetCore|.Net6 gRPC服务开发及本地调试 - 咸鱼Y

 2 years ago
source link: https://www.cnblogs.com/CXY-Blog/p/16460110.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

最近在项目中实装应用了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项目作为服务端 ![](https://img2022.cnblogs.com/blog/855221/202207/855221-20220709130715436-144401422.png)

  • 程序包管理器控制台添加 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 文件包含进去
    855221-20220709131044205-622464125.png

点击查看代码

<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中间件并映射我们写好的服务
    855221-20220709131106616-348001450.png

//启用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的服务端就搞定了,完整的项目结构就变成这样了
    855221-20220709131126288-439829179.png

3、gRPC客户端开发

客户端项目我们也是新建一个webApi项目,并在webapi接口中调用我们的gRPC服务接口获取数据并以json格式输出 * 首先新建一个webApi项目

855221-20220709130953149-374045423.png
  • 程序包管理器控制台添加 Grpc.AspNetCore nuget包引用
    Install-Package Grpc.AspNetCore -Version 2.47.0
  • 新建文件夹proto,并将 gRPCServer项目的 user.proto 文件拷贝过来
  • 右键编辑项目文件,增加一个节点,并把 user.proto 文件包含进去(节点Server属性要设置为 Client)
    855221-20220709131327368-660688362.png
<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服务于客户端调用就搭建好了

    855221-20220709131418943-866186467.png
    855221-20220709131426056-1316498356.png
  • 完整项目结构

    855221-20220709131432804-480257953.png

4、gRPC服务端接口本地调试

grpcServer的接口服务不能像webApi一样直接启动就能进行调试,需要借助一些第三方中间件进行协助测试。我这边使用的是grpcui 进行对本地grpc服务接口的开发调试,下面是grpcui的安装及使用步骤

  • grpcui是Go语言编写的,所以第一步我们先要进行Go环境的搭建。

  • 打开Go官网 ,下载并安装

    855221-20220709145422537-27674583.png
  • 安装完成,以管理员身份打开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
    855221-20220709131604976-2138348520.png

  • 安装完成即可使用命令测试是否安装成功
    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接口
    855221-20220709131707021-413405217.png

  • 启动的WebUI调试页面

    855221-20220709131714137-1877028892.png

在此页面我们就可以像使用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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK