protobuf-net.Grpc 笔记

众所周知,Grpc很好用,但每次都需要手动编写 *.proto 文件,protobuf-net.Grpc个人感觉最大的优势是不用写*.proto 文件,相关教程如下:

https://learn.microsoft.com/zh-cn/aspnet/core/grpc/code-first?view=aspnetcore-8.0

https://protobuf-net.github.io/protobuf-net.Grpc/gettingstarted

 
1. 定义代码协定
创建类库,名称为ProtobufNetShared,安装 protobuf-net.Grpc 和 System.ServiceModel.Primitives

[ServiceContract]
public interface IGreeterService
{
    [OperationContract]
    Task<HelloReply> SayHelloAsync(HelloRequest request);
}

[DataContract]
public class HelloRequest
{
    [DataMember(Order = 1)]
    public string Name { get; set; }
}

[DataContract]
public class HelloReply 
{
    [DataMember(Order = 1)]
    public string Message { get; set; }
}

[Service]
public interface IOrderService
{
    CreateResult CreateOrder(CreateRequest request);
    QueryResult QueryOrder(QueryRequest request);
}

[ProtoContract]
public class CreateRequest
{
    [ProtoMember(1)]
    public string OrderNo { get; set; }

    [ProtoMember(2)]
    public string OrderName { get; set; }

    [ProtoMember(3)]
    public string Price { get; set; }
}

[ProtoContract]
public class CreateResult
{
    [ProtoMember(1)]
    public bool Result { get; set; }

    [ProtoMember(2)]
    public string Message { get; set; }
}

[ProtoContract]
public class QueryRequest
{
    [ProtoMember(1)]
    public int Id { get; set; }
}

[ProtoContract]
public class QueryResult
{
    [ProtoMember(1)]
    public int Id { get; set; }

    [ProtoMember(2)]
    public string OrderNo { get; set; }

    [ProtoMember(3)]
    public string OrderName { get; set; }

    [ProtoMember(4)]
    public double Price { get; set; }
}

前面的代码,SayHello 部分定义了HelloRequest、HelloReply消息 和 使用一元 SayHelloAsync gRPC 方法定义 IGreeterService 协定接口

代码如下:https://gitee.com/Karl_Albright/csharp-demo/tree/master/GrpcDemo/ProtobufNetShared

 

2. 定义Grpc服务

创建 ASP.NET Core Web API 项目,名称为ProtobufNetService,安装 protobuf-net.Grpc.AspNetCore 和 引用 ProtobufNetShared

 创建 GreeterService 并实现 IGreeterService,创建 OrderService 并实现 IOrderService

public class GreeterService : IGreeterService
{
    public Task<HelloReply> SayHelloAsync(HelloRequest request)
    {
        return Task.FromResult(new HelloReply 
        {
            Message = "你好 " + request.Name
        });
    }
}
public class OrderService : IOrderService
{
    public CreateResult CreateOrder(CreateRequest request)
    {
        return new CreateResult
        {
            Result = true,
            Message = "订单创建成功",
        };
    }

    public QueryResult QueryOrder(QueryRequest request)
    {
        return new QueryResult 
        {
            Id = request.Id,
            OrderNo = DateTime.Now.ToString("yyyyMMddHHmmss"),
            OrderName = "冰箱",
            Price = 1288
        };
    }
}

更新 Program 文件 

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        builder.Services.AddCodeFirstGrpc();

        var app = builder.Build();

        app.MapGrpcService<GreeterService>();

        app.MapGrpcService<OrderService>();

        app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");

        app.Run();
    }
}
AddCodeFirstGrpc 注册启用了代码优先的服务。
MapGrpcService<GreeterService> 添加代码优先的服务终结点
appsettings.json配置中增加http2配置

 
3. 创建 Grpc客户端

创建控制台项目,名称叫 ProtobufNetDemo,安装 Grpc.Net.Client 和 protobuf-net.Grpc

 更新 Program.cs 代码

internal class Program
{
    static async Task Main(string[] args)
    {
        using var channel = GrpcChannel.ForAddress("http://localhost:5041");
        var client = channel.CreateGrpcService<IGreeterService>();
        var reply = await client.SayHelloAsync(
        new HelloRequest { Name = "Karl" });

        Console.WriteLine($"Greeting: {reply.Message}");
        Console.WriteLine("Press any key to exit...");
        Console.ReadKey();
    }
}

代码如下:https://gitee.com/Karl_Albright/csharp-demo/tree/master/GrpcDemo/ProtobufNetDemo

先运行 ProtobufNetService,再运行 ProtobufNetDemo 运行结果如下 

 

4. 创建 Web api 客户端

 创建 ASP.NET Core Web API 项目,名称为ProtobufNetClient,安装 protobuf-net.Grpc.AspNetCore、protobuf-net.Grpc.ClientFactory 和 引用 ProtobufNetShared

 增加 Program.cs 代码

builder.Services.AddCodeFirstGrpcClient<IGreeterService>(o =>
{
    o.Address = new Uri("http://localhost:5041/");
    o.ChannelOptionsActions.Add(options =>
    {
        options.HttpHandler = new SocketsHttpHandler()
        {
            // keeps connection alive
            PooledConnectionIdleTimeout = Timeout.InfiniteTimeSpan,
            KeepAlivePingDelay = TimeSpan.FromSeconds(60),
            KeepAlivePingTimeout = TimeSpan.FromSeconds(30),

            // allows channel to add additional HTTP/2 connections
            EnableMultipleHttp2Connections = true
        };
    });
});
builder.Services.AddCodeFirstGrpcClient<IOrderService>(o =>
{
    o.Address = new Uri("http://localhost:5041/");
    o.ChannelOptionsActions.Add(options =>
    {
        options.HttpHandler = new SocketsHttpHandler()
        {
            // keeps connection alive
            PooledConnectionIdleTimeout = Timeout.InfiniteTimeSpan,
            KeepAlivePingDelay = TimeSpan.FromSeconds(60),
            KeepAlivePingTimeout = TimeSpan.FromSeconds(30),

            // allows channel to add additional HTTP/2 connections
            EnableMultipleHttp2Connections = true
        };
    });
});

创建 HelloController 和 OrderController

[ApiController]
[Route("[controller]/[action]")]
public class HelloController : ControllerBase
{
    IGreeterService service;
    public HelloController(IGreeterService service) 
    {
        this.service = service;
    }

    [HttpGet(Name = "Echo")]
    public string Echo(string name)
    {
        return service.SayHelloAsync(new HelloRequest { Name = name }).Result.Message;
    }
}
[ApiController] [Route(
"[controller]/[action]")] public class OrderController : ControllerBase { IOrderService service; public OrderController(IOrderService service) { this.service = service; } [HttpGet(Name = "CreateOrder")] public CreateResult CreateOrder() { return service.CreateOrder(new CreateRequest { OrderNo = DateTime.Now.ToString("yyyyMMddHHmmss"), OrderName = "订单名称", Price = "12.32" }); } [HttpGet(Name = "QueryOrder")] public QueryResult QueryOrder(int id) { return service.QueryOrder(new QueryRequest { Id = id, }); } }

代码地址: https://gitee.com/Karl_Albright/csharp-demo/tree/master/GrpcDemo/ProtobufNetClient

先运行 ProtobufNetService,再运行 ProtobufNetClient 运行结果如下,在Swagger中调用相应的Api

 

 

 

 

posted @ 2024-07-12 17:37  Karl_Albright  阅读(54)  评论(0编辑  收藏  举报