Hosting both GRPC service and REST controller in ASP.NET Core 5.0 application

3.8k views Asked by At

I have a GRPC service written in ASP.NET Core 5.0 and I wanted to add a classic REST controller to explore its inner status during the development phase.

Unfortunately, I am experiencing some issues with routing.

This is the relevant endpoint section of the Startup class

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

    endpoints.MapGrpcService<TestProviderService>();

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

The controller is accessible when hitting /values/ but it can't find the action when trying to explore a specific resource /values/123 or /values/1234/2345. (In my real case, the IDs are GUIDs, not integers, if it makes any difference).

Everything works as expected when I comment out

endpoints.MapGrpcService<TestProviderService>();

I also tried to enable HTTP 1 and HTTP 2 side by side by doing

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

But it didn't help either.

Thanks for your help!

1

There are 1 answers

1
Robert On

We started with a Client Side Blazor Solution and added a GRPC interface to it. This might lead to your desired result. BTW we also added swagger to it.

In the CreateHostBuilder (program.cs) we added UseUrls("https://localhost:44326", "https://localhost:6000"). The HTML is served from 44326 and the GRPC from port 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);
            });

The Startup adds Grpc and RazorPages and so on. In Configure we map the GRPC implementation to port 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");
            });
        });
    }