.net6使用gRPC

一、前言

gRPC 是一种与语言无关的高性能远程过程调用 (RPC) 框架。

gRPC 的主要优点是:

  • 现代高性能轻量级 RPC 框架。
  • 协定优先 API 开发,默认使用协议缓冲区,允许与语言无关的实现。
  • 可用于多种语言的工具,以生成强类型服务器和客户端。
  • 支持客户端、服务器和双向流式处理调用。
  • 使用 Protobuf 二进制序列化减少对网络的使用。

这些优点使 gRPC 适用于:

  • 效率至关重要的轻量级微服务。
  • 需要多种语言用于开发的 Polyglot 系统。
  • 需要处理流式处理请求或响应的点对点实时服务。

引用自微软官方文档: https://docs.microsoft.com/zh-cn/aspnet/core/grpc/?view=aspnetcore-6.0

二、创建gRPC服务

本文使用VS2022+.net6进行演示。

1、通过模板创建gRPC服务

2、文件介绍

greet.proto:协议文件,定义通信的数据结构和服务接口。

GreeterService:服务类,继承的 Greeter.GreeterBase 是根据proto文件自动生成的

Startup.cs:将 gRPC服务添加到了终结点路由中

csproj:项目文件,添加了proto文件引用

三、创建gRPC客户端并调用

1、添加名称为GrpcClient的控制台程序

2、添加Nuget包引用:Grpc.Net.Client、Google.Protobuf、Grpc.Tools

3、将服务的 proto 文件夹复制到客户端。复制后会自动在工程文件中添加引用,注意将GrpcServices值改为Client

4、Program.cs中添加客户端调用代码

var channel = GrpcChannel.ForAddress("https://localhost:5001"); // 服务端地址
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "张三" });
Console.WriteLine("Greeter 服务返回数据: " + reply.Message);
Console.ReadKey();

5、运行服务端和客户端,可以看到客户端接受到了服务端返回的数据

四、创建自己的gRPC服务并调用

我们以注册登录为例。

1、在GrpcService > Protos文件夹新建user.proto文件

定义了注册、登陆、退出、获取所有用户四个方法。

syntax = "proto3";

option csharp_namespace = "GrpcService";

package user;

// 需要使用空参数和空返回值时,需要使用这个协议文件
import "google/protobuf/empty.proto"; 

service User {
  // 注册
  rpc Register (UserDTO) returns (CommonResult);
  // 登陆
  rpc Login (LoginDTO) returns (LoginResult);
  // 退出
  rpc Logout (LogoutDTO) returns (CommonResult);
  // 获取所有用户
  rpc GetAllUser (google.protobuf.Empty) returns (AllUser);
}

message UserDTO {
	string account = 1;
	string pwd = 2;
    string name = 3;
    int32 age = 4;
}

message LoginDTO{
	string accont = 1;
	string pwd = 2;
}

message LoginResult{
	string token = 1;
}

message LogoutDTO{
	string token = 1;
}

message CommonResult {
	string code = 1;
    string message = 2;
}

message AllUser{
	// repeated 表示集合
	repeated UserDTO userList = 1; 
}


注意:Protobuf支持的类型与C#类型是有差异的,对照关系详见:https://docs.microsoft.com/en-us/aspnet/core/grpc/protobuf?view=aspnetcore-6.0#scalar-value-types

2、在GrpcService > Services文件夹新建UserService.cs文件

实现proto中定义的方法

using Google.Protobuf.WellKnownTypes;
using Grpc.Core;

namespace GrpcService.Services
{
    public class UserService : User.UserBase
    {
        private readonly ILogger<UserService> _logger;
        public UserService(ILogger<UserService> logger)
        {
            _logger = logger;
        }

        // 存储注册用户
        private static IList<UserDTO> _userDTOs = new List<UserDTO>();

        /// <summary>
        /// 注册方法实现
        /// </summary>
        /// <param name="userDTO"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override Task<CommonResult> Register(UserDTO userDTO, ServerCallContext context)
        {
            _userDTOs.Add(userDTO);
            return Task.FromResult(new CommonResult
            {
                Code = "2000",
                Message = "注册成功。"
            });
        }

        /// <summary>
        /// 登陆方法实现
        /// </summary>
        /// <param name="userDTO"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override Task<LoginResult> Login(LoginDTO userDTO, ServerCallContext context)
        {
            // TODO...

            return Task.FromResult(new LoginResult
            {
                Token = "TestToken"
            });
        }

        /// <summary>
        /// 退出方法实现
        /// </summary>
        /// <param name="userDTO"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override Task<CommonResult> Logout(LogoutDTO userDTO, ServerCallContext context)
        {
            // TODO...

            return Task.FromResult(new CommonResult
            {
                Code = "2000",
                Message = "退出成功。"
            });
        }

        /// <summary>
        /// 获取所有用户实现
        /// </summary>
        /// <param name="empty"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override Task<AllUser> GetAllUser(Empty empty, ServerCallContext context)
        {
            var allUser = new AllUser();
            allUser.UserList.Add(_userDTOs);

            return Task.FromResult(allUser);
        }
    }
}

3、将UserService添加到终结点路由

4、将GrpcService>Protos>user.proto文件拷贝到GrpcClient>Protos文件夹

5、在GrpcClient>Program.cs文件加入调用代码

里面我用到了Newtonsoft.Json做序列化,需要安装Newtonsoft.Json包。

var channel = GrpcChannel.ForAddress("https://localhost:7145"); // 服务端地址
var client = new User.UserClient(channel);
var reply = await client.RegisterAsync(new UserDTO { Account = "zhangsan", Pwd = "123", Name = "张三", Age = 18 });
Console.WriteLine("User 服务 RegisterAsync 方法返回数据: " + JsonConvert.SerializeObject(reply));
Console.ReadKey();

var reply1 = await client.RegisterAsync(new UserDTO { Account = "lisi", Pwd = "123", Name = "李四", Age = 20 });
Console.WriteLine("User 服务 RegisterAsync 返回数据: " + JsonConvert.SerializeObject(reply1));
Console.ReadKey();

var reply2 = await client.GetAllUserAsync(new Google.Protobuf.WellKnownTypes.Empty());
Console.WriteLine("User 服务 GetAllUserAsync 返回数据: " + JsonConvert.SerializeObject(reply2));
Console.ReadKey();

var reply3 = await client.LoginAsync(new LoginDTO() { Accont = "zhangsan", Pwd = "123" });
Console.WriteLine("User 服务 LoginAsync 返回数据: " + JsonConvert.SerializeObject(reply3));
Console.ReadKey();

var reply4 = await client.LogoutAsync(new LogoutDTO() { Token = "TestToken" });
Console.WriteLine("User 服务 LogoutAsync 返回数据: " + JsonConvert.SerializeObject(reply4));
Console.ReadKey();

至此服务和调用都已完毕,下面开始运行

6、先运行GrpcService,再运行GrpcClient

可以看到返回结果正常

六、总结

本文列出.net6环境下使用gRPC的简单示例。demo地址:https://github.com/gaozejie/gRPCTest

posted @ 2022-02-09 20:24  gaozejie  阅读(1492)  评论(0编辑  收藏  举报