3

Context

The "hosting" mechanism has changed in .NET 6. Previously IWebHost had IWebHost.ServerFeatures property that could be used to get the IServerAddressFeature like so (from this SO answer):

IWebHost host = new WebHostBuilder()
            .UseStartup<Startup>()
            .UseUrls("http://*:0") // This enables binding to random port
            .Build();
host.Start();
foreach(var address in host.ServerFeatures.Get<IServerAddressesFeature>().Addresses) {
  var uri = new Uri(address);
  var port = uri.Port;
  Console.WriteLine($"Bound to port: {port}");
}

Question: how to get the port in .NET 6 with IHost?

Now in .NET 6 I have an IHost. How do I get the port (line with ???):

public class Program {
  public static void Main(string[] args) {
    IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args);
    hostBuilder.ConfigureWebHostDefaults(webHostBuilder => {
      webHostBuilder.ConfigureKestrel(opts => {
        opts.ListenAnyIP(0); // bind web server to random free port
      });
      webHostBuilder.UseStartup<Startup>();
    });
    IHost host = hostBuilder.Build();
    host.Start();
    // If it doesn't fail, at this point Kestrel has started
    // and is listening on a port. It even prints the port to
    // console via logger.
    int boundPort = ???; // some magic GetPort(IHost host) method

    // This link in the docs mentions getting the port, but the example
    // they provide is incomplete
    // https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints?view=aspnetcore-6.0#port-0
    host.WaitForShutdown();
  }
}

The example from Microsoft's docs:

When the port number 0 is specified, Kestrel dynamically binds to an available port. The following example shows how to determine which port Kestrel bound at runtime:

app.Run(async (context) =>
{
    var serverAddressFeature = context.Features.Get<IServerAddressesFeature>();

    if (serverAddressFeature is not null)
    {
        var listenAddresses = string.Join(", ", serverAddressFeature.Addresses);

        // ...
    }
});

In this example, what is the app? Where can I get that context with .Features?

Dmitry Avtonomov
  • 8,747
  • 4
  • 32
  • 45

1 Answers1

4

Found a working answer right after posting the question. Function to print the address of a runing web server (including port) in .NET 6. Turns out we're interested in a running instance of a IServer service in the host.

public static void PrintBoundAddressesAndPorts(IHost host)
{
    Console.WriteLine("Checking addresses...");
    var server = host.Services.GetRequiredService<IServer>();
    var addressFeature = server.Features.Get<IServerAddressesFeature>();
    foreach(var address in addressFeature.Addresses)
    {
        var uri = new Uri(address);
        var port = uri.Port;
        Console.WriteLine($"Listing on [{address}]");
        Console.WriteLine($"The port is [{port}]");
    }
}

Found the answer in this article: https://andrewlock.net/finding-the-urls-of-an-aspnetcore-app-from-a-hosted-service-in-dotnet-6/

Dmitry Avtonomov
  • 8,747
  • 4
  • 32
  • 45