Dapr .NetCore grpc调用
本文介绍如何使用 Dapr 连接使用 gRPC 的服务。通过使用 Dapr 的 gRPC 代理功能,您可以使用现有的基于 proto 的 gRPC 服务并使流量通过 Dapr sidecar。这样做会给开发人员带来以下Dapr 服务调用的好处:
1.相互认证
2.追踪
3.指标
4.访问列表
5.网络级弹性
6.基于 API 令牌的身份验证
创建运行 gRPC 服务器
创建项目
执行如下命令添加grpc服务器项目
dotnet new grpc -n InvokeMethodGRPCServer
修改项目监听端口
修改launchSettings.json中监听端口为5003
,避免与我们客户端监听端口产生冲突(5001
)。
{
"profiles": {
"InvokeMethodGRPCServer": {
"commandName": "Project",
"launchBrowser": false,
"applicationUrl": "http://localhost:5003",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
在Program文件中,添加grpc监听端口5050
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>();
});
添加依赖
<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服务
在创建项目时,我们看见了Services
目录下创建了/Protos/greet.proto
所对应的GreeterService
,我们只需要调用它的SayHello
方法即可
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
});
}
}
在Services
目录下面创建DaprClientService
服务实现AppCallback.AppCallbackBase
,让Dapr识别到grpc的服务的sayhello
方法。
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);
}
}
这里我们需要注入DaprClient
与GreeterService
,但是我们这里并没有对其服务进行注入,所以我们还需要在Startup
类中添加相关服务的依赖注入。
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");
});
});
}
首先我们需要在ListTopicSubscriptions
方法中,发布sayhello
的订阅。
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);
}
然后我们需要在OnInvoke
方法中实现sayHello方法的调用;通过request.Method
的判断方法的名称进行调用不同的case,通过TryUnpack
方法转换将上传的数据转换成指定类型,我们看到SayHello方法是需要HelloRequest类型去进行接受的,所以我们把它转换成指定的类型。
然后,通过output变量获取GreeterService
服务的SayHello
方法的回调。
最后将回调的数据结果用Any.Pack
转换成Any
类型,进行返回。
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服务器
告诉dapr运行的appid为grpcserver
且为grpc服务器,应用grpc开放的端口为5050
,dapr的端口为3500
dapr run --app-id grpcserver --app-protocol grpc --app-port 5050 --dapr-http-port 3500 -- dotnet run
创建客户端
这里我用创建好的InvokeMethod webapi项目。
首先将grpc Protos复制到该项目中,并进行添加相关依赖包与引用。
添加相关服务。
<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>
services.AddControllers().AddDapr();
随后执行dotnet build
进行生成相关类。
创建控制器
创建SendMessageGRPCController控制器,在请求Get方法时进行调用grpc的sayhello方法。
[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}";
}
}
运行客户端
dapr run --app-id myclient --app-port 5001 --dapr-http-port 3501 -- dotnet run
查看启动的应用
测试
访问客户端的http://localhost:5001/SendMessageGRPC
,我们可以看到grpc调用成功
在来Zipin上查看调用情况
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739