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