在 ASP.NET Core 5.0 应用程序中同时托管 GRPC 服务和 REST 控制器

问题描述

我有一个用 ASP.NET Core 5.0 编写的 GRPC 服务,我想添加一个经典的 REST 控制器来在开发阶段探索其内部状态。

很遗憾,我遇到了一些路由问题。

这是 Startup 类的相关端点部分

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();

    endpoints.MapGrpcService<TestProviderService>();

    endpoints.MapGet("/",async context =>
    {
        context.Response.Redirect("/docs/index.html");
    });
});

点击 /values/ 时可以访问控制器,但在尝试探索特定资源 /values/123/values/1234/2345 时找不到操作。 (在我的实际情况中,ID 是 GUID,而不是整数,如果有什么区别的话)。

当我注释掉时,一切都按预期进行

endpoints.MapGrpcService<TestProviderService>();

我还尝试同时启用 HTTP 1 和 HTTP 2

webBuilder.UseStartup<Startup>()
          .ConfigureKestrel(options => options.ConfigureEndpointDefaults(o => o.Protocols = HttpProtocols.Http1AndHttp2));

但这也无济于事。

感谢您的帮助!

解决方法

我们从客户端 Blazor 解决方案开始,并为其添加了 GRPC 接口。这可能会导致您想要的结果。顺便说一句,我们还为它添加了招摇。

在 CreateHostBuilder (program.cs) 中,我们添加了 UseUrls("https://localhost:44326","https://localhost:6000")。 HTML 从 44326 提供,GRPC 从端口 6000 提供。

private static IHostBuilder CreateHostBuilder(string[] args,WebApiClient webApiClient) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>()
                    .UseKestrel()
                    .UseUrls("https://localhost:44326","https://localhost:6000");
            }).ConfigureServices((IServiceCollection services) => {
                services.AddSingleton(webApiClient);
            });

Startup 增加了 Grpc 和 RazorPages 等等。在配置中,我们将 GRPC 实现映射到端口 6000:

       public void ConfigureServices(IServiceCollection services)
    {
        services.AddGrpc();
        services.AddSingleton<IHttpContextAccessor,HttpContextAccessor>();
    }

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

        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHub<ServerUpdatesHub>("/ServerUpdatesHub");
            endpoints.MapControllers();
            endpoints.MapFallbackToFile("index.html");
            endpoints.MapGrpcService<MyGRPCService>().RequireHost($"*:6000");
            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");
            });
        });
    }