Dapr .NetCore grpc调用 电脑版发表于:2021/10/10 12:21 ![](https://img.tnblog.net/arcimg/hb/896fd38e95b346f9a0d98c54b135bb94.jpg) >#Dapr .NetCore grpc调用 [TOC] tn2>本文介绍如何使用 Dapr 连接使用 gRPC 的服务。通过使用 Dapr 的 gRPC 代理功能,您可以使用现有的基于 proto 的 gRPC 服务并使流量通过 Dapr sidecar。这样做会给开发人员带来以下Dapr 服务调用的好处:<br/> 1.相互认证 2.追踪 3.指标 4.访问列表 5.网络级弹性 6.基于 API 令牌的身份验证 创建运行 gRPC 服务器 ------------ >### 创建项目 tn2>执行如下命令添加grpc服务器项目 ```bash dotnet new grpc -n InvokeMethodGRPCServer ``` >###修改项目监听端口 tn2>修改launchSettings.json中监听端口为`5003`,避免与我们客户端监听端口产生冲突(`5001`)。 ```bash { "profiles": { "InvokeMethodGRPCServer": { "commandName": "Project", "launchBrowser": false, "applicationUrl": "http://localhost:5003", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } ``` tn2>在Program文件中,添加grpc监听端口`5050` ```csharp public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.ConfigureKestrel(options => { options.ListenLocalhost(5050, o => o.Protocols = HttpProtocols.Http2); }); webBuilder.UseStartup<Startup>(); }); ``` >### 添加依赖 ```bash <ItemGroup> <PackageReference Include="Grpc.AspNetCore" Version="2.27.0" /> <PackageReference Include="Dapr.AspNetCore" Version="1.4.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Google.Api.CommonProtos" Version="2.4.0" /> </ItemGroup> ``` >### 创建grpc服务 tn2>在创建项目时,我们看见了`Services`目录下创建了`/Protos/greet.proto`所对应的`GreeterService`,我们只需要调用它的`SayHello`方法即可 ```csharp public class GreeterService : Greeter.GreeterBase { private readonly ILogger<GreeterService> _logger; public GreeterService(ILogger<GreeterService> logger) { _logger = logger; } public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context) { return Task.FromResult(new HelloReply { Message = "Hello " + request.Name }); } } ``` tn2>在`Services`目录下面创建`DaprClientService`服务实现`AppCallback.AppCallbackBase`,让Dapr识别到grpc的服务的`sayhello`方法。 ```csharp public class DaprClientService:AppCallback.AppCallbackBase { private readonly GreeterService _service; private readonly DaprClient _daprclient; public DaprClientService( GreeterService service, DaprClient daprclient ){ _service = service; _daprclient = daprclient; } public override async Task<InvokeResponse> OnInvoke(InvokeRequest request, ServerCallContext context) { var response = new InvokeResponse(); switch (request.Method) { case "sayhello": if (request.Data.TryUnpack<HelloRequest>(out HelloRequest input)) { var output = await _service.SayHello(input,context); response.Data = Any.Pack(output); } break; default: break; } return response; } public override Task<ListInputBindingsResponse> ListInputBindings(Empty request, ServerCallContext context) { return base.ListInputBindings(request, context); } public override Task<ListTopicSubscriptionsResponse> ListTopicSubscriptions(Empty request, ServerCallContext context) { var result = new ListTopicSubscriptionsResponse(); result.Subscriptions.Add(new TopicSubscription { PubsubName = "pubsub", Topic = "sayhello" }); return Task.FromResult(result); } public override Task<BindingEventResponse> OnBindingEvent(BindingEventRequest request, ServerCallContext context) { return base.OnBindingEvent(request, context); } public override Task<TopicEventResponse> OnTopicEvent(TopicEventRequest request, ServerCallContext context) { return base.OnTopicEvent(request, context); } } ``` tn2>这里我们需要注入`DaprClient`与`GreeterService`,但是我们这里并没有对其服务进行注入,所以我们还需要在`Startup`类中添加相关服务的依赖注入。 ```csharp public void ConfigureServices(IServiceCollection services) { services.AddGrpc(); services.AddDaprClient(); services.AddTransient<GreeterService>(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGrpcService<DaprClientService>(); endpoints.MapGet("/", async context => { await context.Response.WriteAsync("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"); }); }); } ``` tn2>首先我们需要在`ListTopicSubscriptions`方法中,发布`sayhello`的订阅。 ```csharp public override Task<ListTopicSubscriptionsResponse> ListTopicSubscriptions(Empty request, ServerCallContext context) { var result = new ListTopicSubscriptionsResponse(); result.Subscriptions.Add(new TopicSubscription { PubsubName = "pubsub", Topic = "sayhello" }); return Task.FromResult(result); } ``` tn2>然后我们需要在`OnInvoke`方法中实现sayHello方法的调用;通过`request.Method`的判断方法的名称进行调用不同的case,通过`TryUnpack`方法转换将上传的数据转换成指定类型,我们看到SayHello方法是需要HelloRequest类型去进行接受的,所以我们把它转换成指定的类型。 然后,通过output变量获取`GreeterService`服务的`SayHello`方法的回调。 最后将回调的数据结果用`Any.Pack`转换成`Any`类型,进行返回。 ```csharp public override async Task<InvokeResponse> OnInvoke(InvokeRequest request, ServerCallContext context) { var response = new InvokeResponse(); switch (request.Method) { case "sayhello": if (request.Data.TryUnpack<HelloRequest>(out HelloRequest input)) { var output = await _service.SayHello(input,context); response.Data = Any.Pack(output); } break; default: break; } return response; } ``` >### 运行grpc服务器 tn2>告诉dapr运行的appid为`grpcserver`且为grpc服务器,应用grpc开放的端口为`5050`,dapr的端口为`3500` ```bash dapr run --app-id grpcserver --app-protocol grpc --app-port 5050 --dapr-http-port 3500 -- dotnet run ``` ![](https://img.tnblog.net/arcimg/hb/1bb5c01ea45a49d48cf8ba58f02ade1c.png) 创建客户端 ------------ tn2>这里我用创建好的InvokeMethod webapi项目。 首先将grpc Protos复制到该项目中,并进行添加相关依赖包与引用。 添加相关服务。 ![](https://img.tnblog.net/arcimg/hb/2a2ff4c0f87542dc96fb2b2bd485e988.png) ```xml <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> </PropertyGroup> <ItemGroup> <Protobuf Include="Protos\greet.proto" GrpcServices="Client" ProtoRoot="Protos\" /> </ItemGroup> <ItemGroup> <PackageReference Include="Grpc.AspNetCore" Version="2.27.0" /> <PackageReference Include="Dapr.AspNetCore" Version="1.4.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> </ItemGroup> </Project> ``` ```csharp services.AddControllers().AddDapr(); ``` tn2>随后执行`dotnet build`进行生成相关类。 >###创建控制器 tn2>创建SendMessageGRPCController控制器,在请求Get方法时进行调用grpc的sayhello方法。 ```csharp [ApiController] [Route("[controller]")] public class SendMessageGRPCController { private readonly ILogger<SendMessageGRPCController> _logger; private readonly DaprClient _client; public SendMessageGRPCController(ILogger<SendMessageGRPCController> logger,DaprClient client ) { _logger = logger; _client = client; } [HttpGet] public async Task<string> Get() { var request = new HelloRequest(){ Name = "GRPC_Client" }; // appid 方法名 var result = await _client.InvokeMethodGrpcAsync<HelloRequest,HelloReply>("grpcserver","sayhello",request); return $"ok! {result.Message}"; } } ``` >### 运行客户端 ```bash dapr run --app-id myclient --app-port 5001 --dapr-http-port 3501 -- dotnet run ``` ![](https://img.tnblog.net/arcimg/hb/3d1715646a474173b2caa8f84d7eeac1.png) >### 查看启动的应用 ![](https://img.tnblog.net/arcimg/hb/bfce6ebfa0984635b26be557a248c0f2.png) 测试 ------------ tn2>访问客户端的`http://localhost:5001/SendMessageGRPC`,我们可以看到grpc调用成功 ![](https://img.tnblog.net/arcimg/hb/0ec6889cdbf44acc9c6e905bd512edec.png) tn2>在来Zipin上查看调用情况 ![](https://img.tnblog.net/arcimg/hb/b7491d2894cd419c963a7f2af6adcbd2.png)