(二) gRPC初探之代码优先方法进行 API 开发

我们接着上一篇 (一) gRPC初探之协定优先方法进行 API 开发 来讲,基于proto协定优先的方式开发服务是在不限语言的基础上,当整个系统使用 .NET开发时,我们可以使用代码优先:

  • 可以在 .NET 服务器和客户端之间共享 .NET 服务和数据协定类型
  • 无需在 .proto 文件和代码生成过程中定义协定

protobuf-net.Grpc

基于 .NET版本的gRPC社区开源项目.通过属性注解的 .NET 类型来定义应用的 gRPC 服务和消息

项目结构

image

创建服务和数据协定类型

  • 创建GrpcService1.Shared项目并添加 protobuf-net.Grpc 包引用
  • 创建出参/入参并定义接口
  • 添加属性批注
namespace GrpcService1.Shared
{
    using System.Runtime.Serialization;
    [DataContract]
    public class CreateOrderInput
    {
        [DataMember(Order = 1)]
        public int BuyerId { get; set; }

        [DataMember(Order = 2)]
        public string BuyerName { get; set; }

        [DataMember(Order = 3)]
        public int OrderId { get; set; }

        [DataMember(Order = 4)]
        public string OrderName { get; set; }
    }
}


namespace GrpcService1.Shared
{
    using System.Runtime.Serialization;
    [DataContract]
    public class CreateOrderOutput
    {
        [DataMember(Order = 1)]
        public int BuyerId { get; set; }

        [DataMember(Order = 2)]
        public string BuyerName { get; set; }

        [DataMember(Order = 3)]
        public int OrderId { get; set; }

        [DataMember(Order = 4)]
        public string OrderName { get; set; }
    }
}


namespace GrpcService1.Shared
{
    using ProtoBuf.Grpc;
    using System.ServiceModel;
    using System.Threading.Tasks;

    [ServiceContract]
    public interface IOrderService
    {
        [OperationContract]
        Task<CreateOrderOutput> CreateOrderAsync(CreateOrderInput request, CallContext context = default);
    }
}

创建代码优先gRPC服务

  • 创建 GrpcService1API
  • 添加protobuf-net.Grpc.AspNetCore包引用
  • 添加 GrpcService1.Shared项目引用
  • 在项目路径添加/Service/OrderService.cs代码如下
namespace GrpcService1.Shared
{
    using ProtoBuf.Grpc;
    using System.Threading.Tasks;
    public class OrderService : IOrderService
    {
        public async Task<CreateOrderOutput> CreateOrderAsync(CreateOrderInput request, CallContext context = default)
        {
            return await Task.FromResult(new CreateOrderOutput
            {
                BuyerId = request.BuyerId,
                BuyerName = request.BuyerName,
                OrderId = request.OrderId,
                OrderName = request.OrderName,
            });
        }
    }
}
  • 配置Startup.cs
namespace GrpcService1
{
    using GrpcService1.Services;

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;

    using ProtoBuf.Grpc.Server;

    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            // 关键代码
            services.AddCodeFirstGrpc();//注册启用了代码优先的服务。
            // 关键代码
            
            
            services.AddLogging(options => 
            {
                options.AddConsole();
            });

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            var log = app.ApplicationServices.GetService<ILoggerFactory>()?.CreateLogger(env.ApplicationName);
            log.LogInformation("Hello world");
            app.UseEndpoints(endpoints =>
            {
                 // 关键代码 
                endpoints.MapGrpcService<OrderService>();//添加代码优先的服务终结点。
                 // 关键代码
                 
                 
                //endpoints.MapGet("/", async context =>
                // {
                //    await context.Response.WriteAsync("Hello world");
                // });
            });
        }
    }
}

创建代码优先gRPC客户端

  • 创建 dotnetcore 控制台应用程序
  • 添加 Grpc.Net.Client包引用
  • 添加protobuf-net.Grpc引用
namespace GrpcClient1
{
    using Grpc.Net.Client;
    using GrpcService1.Shared;
    using ProtoBuf.Grpc.Client;

    using System;
    using System.Net.Http;
    using System.Text.Json;
    using System.Text.Unicode;
    using System.Threading.Tasks;
    class Program
    {
        static async Task Main(string[] args)
        {
            //  使用不受信任/无效证书调用 gRPC 服务
            var httpHandler = new HttpClientHandler();
            httpHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

            using var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpHandler = httpHandler });
            var client = channel.CreateGrpcService<IOrderService>();

            var result = await client.CreateOrderAsync(new CreateOrderInput
            {
                BuyerId = 1,
                BuyerName = "张小三",
                OrderId = 1,
                OrderName = "方便面",
            });
            var options = new JsonSerializerOptions();
            options.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All);
            Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(result, options));
            Console.ReadKey();
             
        }
    }
}

控制台输出:

image

示例已上传到本人github

posted @ 2021-04-02 17:27  无敌土豆  阅读(381)  评论(3编辑  收藏  举报