Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bind gRPC services to specific port in aspnetcore

Using aspnetcore 3.1 and the Grpc.AspNetCore nuget package, I have managed to get gRPC services running successfully alongside standard asp.net controllers as described in this tutorial.

However I would like to bind the gRPC services to a specific port (e.g. 5001), preferably through configuration instead of code if possible. This is because I would like to limit how my gRPC services are exposed.

The closest I have come has been using RequireHost when mapping the endpoints:

// Startup.cs
public void Configure(IApplicationBuilder app)
{
    // ...
    
    app.useEndpoints(endpoints => 
    {
        endpoints.MapGrpcService<MyService>()
            .RequireHost("0.0.0.0:5001");
    }); 
}

This seems to do what I want but I can't find any documentation about it, and it requires configuration in code per service. Perhaps there is a better way?

like image 235
Laurence Avatar asked Sep 10 '20 10:09

Laurence


People also ask

What is the default port for gRPC?

To open a gRPC connection to a service so you can send gRPC messages, you need to specify the host domain, which is the URL of the Cloud Run service or the custom domain mapped to that service, along with the port 443, which is the port expected to be used by gRPC.

Does gRPC use endpoints?

Kestrel endpoints used for gRPC should be secured with TLS. In development, an endpoint secured with TLS is automatically created at https://localhost:5001 when the ASP.NET Core development certificate is present. No configuration is required. An https prefix verifies the Kestrel endpoint is using TLS.

How to create gRPC service application in ASP NET Core?

Click on ASP.NET Core Web Application and click "Next". Enter your project name and click the "Create" button. Now, we can see that ASP.NET Core 3.0 has been listed. We Select the gRPC Service and click create to create our gRPC service application.

How to set a specific port for gRPC service?

As far as I know, there is no other way to set a specific port for the GRPC service. The grpc service is also running on the asp.net core kestrel server, the server will listen the port not the service. If your asp.net core application just has GRPC service, you could just set the kestrel server's listen port to 5001.

Can I use gRPC with Azure App service or IIS?

ASP.NET Core gRPC has extra requirements for being used with Azure App Service or IIS. For more information on where gRPC can be used, see gRPC on .NET supported platforms. The Visual Studio Code instructions use the .NET Core CLI for ASP.NET Core development functions such as project creation.

What port does Kestrel use for gRPC?

The grpc service is also running on the asp.net core kestrel server, the server will listen the port not the service. If your asp.net core application just has GRPC service, you could just set the kestrel server's listen port to 5001.


5 Answers

This works (server side) with Kestrel:

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
    webBuilder.ConfigureKestrel(options =>
    {
       options.Listen(IPAddress.Loopback, 5000);
       options.Listen(IPAddress.Loopback, 5005, configure => configure.UseHttps());
    });
    webBuilder.UseStartup<Startup>();
});

client side:

 var httpHandler = new HttpClientHandler
 {
     ServerCertificateCustomValidationCallback =
     HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
 };  

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
                
using var channel = GrpcChannel.ForAddress("https://localhost:5005", new GrpcChannelOptions { HttpHandler = httpHandler } );
            
var client = new Greeter.GreeterClient(channel);

Note:

 var httpHandler = new HttpClientHandler
 {
     ServerCertificateCustomValidationCallback =
     HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
 };  

when you have a self-signed certificate without a trust chain (mostly when developing).

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

Is for support of http.

like image 126
Martin.Martinsson Avatar answered Oct 18 '22 22:10

Martin.Martinsson


You need to configure the middleware

app.UseRouting();
app.MapWhen(context => {
   return context.Connection.LocalPort == 1000
}, newApp => {
   newApp.UseRouting();
   newApp.UseEndpoints(endpoints =>
   {
        endpoints.MapGrpcService<Service1>();
   }
});
app.MapWhen(context => {
   return context.Connection.LocalPort == 2000
}, newApp => {
   newApp.UseRouting();
   newApp.UseEndpoints(endpoints =>
   {
        endpoints.MapGrpcService<Service2>();
   }
});
like image 30
Martin Kosicky Avatar answered Oct 18 '22 22:10

Martin Kosicky


As far as I know, there is no other way to set a specific port for the GRPC service.

The grpc service is also running on the asp.net core kestrel server, the server will listen the port not the service.

If your asp.net core application just has GRPC service, you could just set the kestrel server's listen port to 5001.

If you have multiple service like MVC web api or else, RequireHost is the best workaround to allow only specific port access the grpc service.

If you want to prompt the routing system for GRPC service to require the specified port, you could use below port:

 routes.MapGrpcService<MyService>().RequireHost("*:5001");
like image 4
Brando Zhang Avatar answered Oct 18 '22 20:10

Brando Zhang


In the ASP.NET Core 6.0 ports can be changed in the Properties > launchSettings.json file. But this file is considered only if you run the server from the Visual Studio or VS Code.

I was trying to run the server directly using the .exe file for testing. The server was running with the default ports: "http://localhost:5000;https://localhost:5001".

Finally, I changed it from the appsettings.json for the .exe file:

  "AllowedHosts": "*",
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "https://localhost:7005",
        "Protocols": "Http1AndHttp2"
      },
      "gRPC": {
        "Url": "http://localhost:5005",
        "Protocols": "Http2"
      }
    }
like image 3
L_J Avatar answered Oct 18 '22 20:10

L_J


You can try to use the UseWhen method to use the MapGrpcService endpoints only when the request uses the port you defined.

var grpcPort = 5001;
app.UseWhen(context => context.Connection.LocalPort == grpcPort,
    builder =>
    {
        builder.UseRouting();
        builder.UseEndpoints(endpoints =>
        {
            endpoints.MapGrpcService<MyService>();
        });
    });

This has the benefit of not repeating .RequireHost("*:5001"); for every single service, although repeating UseRouting twice may induce weird behaviour: for instance, authentication may not be working unless you put in builder.UseAuthentication() after builder.UseRouting().

However, this behaviour be useful if you want to have a distinct request pipeline for REST and gRPC.

like image 1
jeuxjeux20 Avatar answered Oct 18 '22 20:10

jeuxjeux20