• 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;
            }
    

  • 相关阅读:
    Feature fake , new view in comment.
    MeeGo Architect
    小米手机 怪诞行为经济学
    [转载]ten years as a programmer
    C++ 头文件
    关于AGILE/TDD 和传统的design
    你是否在开发正确的产品
    正确的创业
    MeeGo架构
    Unit Test
  • 原文地址:https://www.cnblogs.com/tangge/p/15221300.html
Copyright © 2020-2023  润新知