grpc的.net core使用

公共数据

InMemoryData.cs

    public class InMemoryData
    {
        public static List<Employee> Employees = new List<Employee>
        {
            new Employee
            {
                Id = 10001,
                No= 2000,
                FirstName = "张",
                LastName = "飞",
                Salary = 3500
            },
            new Employee
            {
                Id = 10002,
                No= 1990,
                FirstName = "刘",
                LastName = "备",
                Salary = 5500
            },
            new Employee
            {
                Id = 10003,
                No= 1995,
                FirstName = "关",
                LastName = "羽",
                Salary = 4500
            },
        };
    }

创建proto

创建一个文件夹Protos, 并且创建一个文件

Messages.proto

syntax = "proto3";

option csharp_namespace = "GrpcServer.Web.Protos";

message Employee{
	int32 id = 1;
	int32 no = 2;
	string firstName = 3;
	string lastName = 4;
	float  salary = 5;
}

message GetByNoRequest{
	int32 no =1;
}

message EmployeeRequest{
	Employee employee = 1;
}

message EmployeeResponse{
	Employee employee = 1;
}

message GetAllRequest{}

message AddPhotoRequest{
	bytes data = 1;
}

message AddPhotoResponse{
	bool isOk = 1;
}

service EmployeeService{
	rpc GetByNo (GetByNoRequest) returns(EmployeeResponse);
	rpc GetAll (GetAllRequest) returns(stream EmployeeResponse);
	rpc AddPhoto (stream AddPhotoRequest) returns (AddPhotoResponse);
	rpc Save (EmployeeRequest) returns (EmployeeResponse);
	rpc SaveAll (stream EmployeeRequest) returns (stream EmployeeResponse);
}

然后设置属性。

设置后生成一次应用程序生成。

1 一元消息

rpc GetByNo (GetByNoRequest) returns(EmployeeResponse);

Service

安装包

Grpc.AspNetCore

配置Startup.cs

services.AddGrpc(); //service 注册

app.UseEndpoints(endpoints =>
{
	endpoints.MapGrpcService<MyEmployeeService>(); //将传入请求映射到指定的 TService 类型。
});

编写 Service

using Grpc.Core;
using GrpcServer.Web.Data;
using GrpcServer.Web.Protos;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace GrpcServer.Web.Services
{
    public class MyEmployeeService : EmployeeService.EmployeeServiceBase
    {
        public readonly ILogger<MyEmployeeService> _logger;
        public MyEmployeeService(ILogger<MyEmployeeService> logger)
        {
            _logger = logger;
        }

        public override Task<EmployeeResponse> GetByNo(GetByNoRequest request, ServerCallContext context)
        {
            var employee = InMemoryData.Employees
                            .SingleOrDefault(x => x.No == request.No);

            //client 发送的元数据(Metadata)
            var metadata = context.RequestHeaders;

            foreach (var item in metadata)
            {
                _logger.LogInformation($"Metadata RequestHeaders: {item.Key}:{item.Value}");
            }

            if (employee is not null)
            {
                var response = new EmployeeResponse
                {
                    Employee = employee
                };

                return Task.FromResult(response);
            }
            throw new Exception(message: $"employee is null.");
            //return base.GetByNo(request, context);
        }
    }
}

Client

安装包

Google.Protobuf Potobuf 序列化协议的包

Grpc.Net.Client 客户端的包

Grpc.Tools 命令行工具

编写 Client

using Grpc.Core;
using Grpc.Net.Client;
using GrpcServer.Web.Protos;
using System;
using System.Threading.Tasks;

namespace GrpcClient
{
    class Program
    {
        static async Task Main(string[] args)
        {
            using var channel = GrpcChannel.ForAddress("https://localhost:5001");
            var client = new EmployeeService.EmployeeServiceClient(channel);
			//发送给sevice的元数据
            var header = new Metadata
            {
                 { "role","Admin"},
                { "username","testAdmin"}
             };
            var response = await client.GetByNoAsync(new GetByNoRequest
            {
                No = 1995
            }, header);

            Console.WriteLine($"message:{response}");
            Console.WriteLine("Press key to exit.");
            Console.ReadLine();
        }
    }
}

结果:

message:{ "employee": { "id": 10003, "no": 1995, "firstName": "关", "lastName": "羽", "salary": 4500 } }
Press key to exit.

Service输出结果:

2 server streaming

rpc GetAll (GetAllRequest) returns(stream EmployeeResponse);

编写 Service

using Grpc.Core;
using GrpcServer.Web.Data;
using GrpcServer.Web.Protos;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace GrpcServer.Web.Services
{
    public class MyEmployeeService : EmployeeService.EmployeeServiceBase
    {
        public readonly ILogger<MyEmployeeService> _logger;
        public MyEmployeeService(ILogger<MyEmployeeService> logger)
        {
            _logger = logger;
        }


        public override async Task GetAll(GetAllRequest request, IServerStreamWriter<EmployeeResponse> responseStream, ServerCallContext context)
        {
            foreach (var employee in InMemoryData.Employees)
            {
                await responseStream.WriteAsync(new EmployeeResponse
                {
                    Employee = employee
                });
            }
        }
    }
}

编写 Client

        public static async Task GetAllAsync(EmployeeService.EmployeeServiceClient client)
        {
            //AsyncServerStreamingCall<global::GrpcServer.Web.Protos.EmployeeResponse>
            using var call = client.GetAll(new GetAllRequest());
            //IAsyncStreamReader<EmployeeResponse>
            var responseStream = call.ResponseStream; 

            while (await responseStream.MoveNext())
            {
                Console.WriteLine(responseStream.Current.Employee);
            }
        }

结果:

{ "id": 10001, "no": 2000, "firstName": "张", "lastName": "飞", "salary": 3500 }
{ "id": 10002, "no": 1990, "firstName": "刘", "lastName": "备", "salary": 5500 }
{ "id": 10003, "no": 1995, "firstName": "关", "lastName": "羽", "salary": 4500 }
Press key to exit.

3 Client Stream

rpc AddPhoto (stream AddPhotoRequest) returns (AddPhotoResponse);

编写 Service

        public override async Task<AddPhotoResponse> AddPhoto(IAsyncStreamReader<AddPhotoRequest> requestStream, ServerCallContext context)
        {
            var data = new List<byte>();
            while (await requestStream.MoveNext())
            {
                Console.WriteLine($"Received:{requestStream.Current.Data.Length} ");
                data.AddRange(requestStream.Current.Data);
            }

            Console.WriteLine($"Recevicd file with { data.Count} bytes.");

            return new AddPhotoResponse { IsOk = true };
        }

编写 Client

        public static async Task AddPhotoAsync(EmployeeService.EmployeeServiceClient client)
        {
            FileStream fs = File.OpenRead(path: "grpc-test.jpg");
            //AsyncClientStreamingCall<global::GrpcServer.Web.Protos.AddPhotoRequest, global::GrpcServer.Web.Protos.AddPhotoResponse>
            using var call = client.AddPhoto();
            //IClientStreamWriter<AddPhotoRequest>
            var requestStream = call.RequestStream;

            while (true)
            {
                byte[] buffer = new byte[1024];
                int num = await fs.ReadAsync(buffer, 0, buffer.Length);
                if (num == 0)
                {
                    break;
                }
                if (num < buffer.Length)
                {
                    //指定最后数组的大小为剩余量
                    Array.Resize(ref buffer, num);
                }
                await requestStream.WriteAsync(new AddPhotoRequest()
                {
                    Data = ByteString.CopyFrom(buffer)
                });
            }

            await requestStream.CompleteAsync();

            var res = await call.ResponseAsync;

            Console.WriteLine(res);
        }

结果:

4 双向 streaming

rpc SaveAll (stream EmployeeRequest) returns (stream EmployeeResponse);

编写 Service

        public override async Task SaveAll(IAsyncStreamReader<EmployeeRequest> requestStream, IServerStreamWriter<EmployeeResponse> responseStream, ServerCallContext context)
        {
            while (await requestStream.MoveNext())
            {
                var employee = requestStream.Current.Employee;
                InMemoryData.Employees.Add(employee);

                await responseStream.WriteAsync(new EmployeeResponse
                {
                    Employee = employee
                });

                Console.WriteLine($"Employees:");
                foreach (var item in InMemoryData.Employees)
                {
                    Console.WriteLine(item);
                }
            }
        }

编写 Client

public static async Task SaveAllAsync(EmployeeService.EmployeeServiceClient client)
        {
            var employees = new List<Employee>() {
            new Employee
            {
                Id = 10011,
                No = 1800,
                FirstName = "诸",
                LastName = "葛亮",
                Salary = 3500
            },
            new Employee
            {
                Id = 10012,
                No = 1990,
                FirstName = "刘",
                LastName = "阿斗",
                Salary = 5500
            } };

            using var call = client.SaveAll();

            var requestStream = call.RequestStream;
            var responseStream = call.ResponseStream;

            var responseTask = Task.Run(async () =>
            {
                while (await responseStream.MoveNext())
                {
                    Console.WriteLine($"Saved: {responseStream.Current.Employee}");
                }
            });

            foreach (var employee in employees)
            {
                await requestStream.WriteAsync(new EmployeeRequest
                {
                    Employee = employee
                });
            }
            await requestStream.CompleteAsync(); //先request complete 才能 responseTask
            await responseTask;
        }

posted @ 2021-09-02 23:22  【唐】三三  阅读(302)  评论(0编辑  收藏  举报