基于Dapr + .NET Aspire搭建gRPC服务间调用遇阻求助
Aspire + Dapr gRPC服务调用失败问题求助
我已按照Aspire官方Dapr HTTP客户端示例完成配置,但gRPC场景下服务间调用无法正常运行。已通过.proto文件完成服务端与客户端的代码生成,不过客户端发起请求时触发内部服务器错误,报错信息如下:
RpcException: Status(StatusCode="Internal", Detail: "failed to invoke, id: service2, err: rpc error: code = Internal desc = error invoking app channel: rpc error: code = InvalidArgument desc = missing HTTP extension field") InvocationException: An exception occurred while invoking method: 'SayHello' on app-id: 'service2' Dapr.Client.DarpClientGrpc.InvokeMethodGrpcAsync<TRequest, TResponse>(string appId, string methodName, TRequest data, CancellationToken cancellationToken)
推测问题原因可能是默认协议为HTTP,需要指定gRPC端点调用,或者需要创建拦截器发送路由所需的额外元数据。
请问是否有经官方验证、可在Aspire环境下稳定运行的gRPC + Dapr调用方案?目前相关文档不完善,现有示例的类似配置在使用protobuf生成的gRPC客户端时往往无法正常工作,这个方案也能帮助其他遇到同样问题的开发者。
当前配置代码示例
AppHost 配置
using CommunityToolkit.Aspire.Hosting.Dapr; using System.Security.Cryptography; var builder = DistributedApplication.CreateBuilder(args); var stateStore = builder.AddDaprStateStore("statestore"); var pubSub = builder.AddDaprPubSub("pubsub"); var bytes = new byte[50]; RandomNumberGenerator.Fill(bytes); var daprApiKey = string.Join("", bytes.Select(b => b.ToString("x2"))); builder.AddProject<Projects.TestService1>("service1") .WithDaprSidecar(b => b.WithOptions(new DaprSidecarOptions(){Config = $"../{nameof(Projects.TestService1)}/resources/dapr/config.yaml",}).WithAnnotation(new EnvironmentCallbackAnnotation("APP_API_TOKEN", () => daprApiKey))) .WithReference(stateStore) .WithEnvironment("APP_API_TOKEN", daprApiKey) .WithReference(pubSub); builder.AddProject<Projects.TestService2>("service2") .WithDaprSidecar(b => b.WithOptions(new DaprSidecarOptions(){Config = $"../{nameof(Projects.TestService2)}/resources/dapr/config.yaml",}).WithAnnotation(new EnvironmentCallbackAnnotation("APP_API_TOKEN", () => daprApiKey))) .WithReference(stateStore) .WithEnvironment("APP_API_TOKEN", daprApiKey) .WithReference(pubSub); // ... }
Service 1 (调用方) 代码
using Dapr.Client; using Grpc.Core; using Grpc.Net.Client; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using TestService1.Clients; using TestService2; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddOpenApi(); builder.Services.AddDaprClient(); // Adds Dapr authentication. By default, the token will be read from the APP_API_TOKEN environment variable. builder.Services.AddAuthentication().AddDapr(); builder.Services.AddAuthorization(options => { // Adds Dapr authorization. The authentication scheme is "Dapr." options.AddDapr(); }); var invoker = DaprClient.CreateInvocationInvoker(appId: "service2", daprApiToken:Environment.GetEnvironmentVariable("APP_API_TOKEN")); var greetClient = new Greeter.GreeterClient(invoker); builder.Services.AddSingleton<Greeter.GreeterClient>(greetClient); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.MapOpenApi(); } app.UseHttpsRedirection(); app.MapGet("/weatherforecast", async (DaprClient client, [FromQuery] int pageSize = 10) => { return await new WeatherClient(client).GetWeatherForecastAsync(pageSize); }) .WithName("GetWeatherForecast"); app.MapGet("/greet", async (DaprClient client, [FromQuery] string name) => { return await client.InvokeMethodGrpcAsync<HelloRequest, HelloReply>("service2", "SayHello", new HelloRequest { Name = name }); //return await client.SayHelloAsync(new HelloRequest() { Name = name }); }) .WithName("GetGreet"); app.Run(); public record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) { public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); } //...
Service 1 项目文件
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net9.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> <ItemGroup> <PackageReference Include="Dapr.AspNetCore" Version="1.15.2" /> <PackageReference Include="Dapr.Client" Version="1.15.2" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.2"/> <PackageReference Include="Grpc.Tools" Version="2.36.1"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup> <ItemGroup> <Protobuf Include="../TestService2/resources/protos/greet.proto" GrpcServices="Server,Client" /> </ItemGroup> </Project>
Service 2 (被调用方) 代码
using Grpc.Net.Client; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using System.Reflection; using TestService2.Controllers.GRPC; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddOpenApi(); builder.Services.AddDaprClient(); builder.Services.AddGrpc(); builder.Services.AddControllers(); // Adds Dapr authentication. By default, the token will be read from the APP_API_TOKEN environment variable. builder.Services.AddAuthentication().AddDapr(); builder.Services.AddAuthorization(options => { // Adds Dapr authorization. Authentication scheme is "Dapr" options.AddDapr(); }); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.MapOpenApi(); } app.UseAuthentication(); app.UseAuthorization(); //app.UseHttpsRedirection(); //app.UseRouting(); app.MapGrpcService<GreeterService>(); app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client."); app.MapControllers(); app.Run();
Service 2 项目文件
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net9.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> <ItemGroup> <PackageReference Include="Dapr.AspNetCore" Version="1.15.2" /> <PackageReference Include="Grpc.AspNetCore.Server" Version="2.70.0" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.2"/> <PackageReference Include="Grpc.Tools" Version="2.36.1"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup> <ItemGroup> <Protobuf Include="resources/protos/greet.proto" GrpcServices="Server,Client" /> </ItemGroup> </Project>
补充说明:浏览器请求Service 2,再由Service 2请求Service 1。已成功搭建Aspire环境下基于HTTP协议的Dapr Sidecar服务间调用,但gRPC场景始终失败。
内容的提问来源于stack exchange,提问作者Brevyn Kurt
相关产品推荐
相关产品推荐

