15

I've got an ASP.NET Core 2.0 app which I intend to run as a stand-alone application. The app should start up and bind to an available port. To achieve this I configure the WebHostBuilder to listen on "http://127.0.0.1:0" and to use the Kestrel server. Once the web host starts listening I want to save the url with the actual port in a file. I want to do this as early as possible, since another application will read the file to interact with my app.

How can I determine the port the web host is listening on?

Christo
  • 1,802
  • 4
  • 20
  • 31

5 Answers5

16

You can achive it in Startup class in method Configure. You can get port from ServerAddressesFeature

Here is an example of code:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, ILogger<Startup> logger)
{
     var serverAddressesFeature = app.ServerFeatures.Get<IServerAddressesFeature>();

     loggerFactory.AddFile("logs/myfile-{Date}.txt", minimumLevel: LogLevel.Information, isJson: false);

     logger.LogInformation("Listening on the following addresses: " + string.Join(", ", serverAddressesFeature.Addresses));
}
Oleg Lukash
  • 291
  • 2
  • 7
12

You can use the Start() method instead of Run() to access IServerAddressesFeature at the right moment:

IWebHost webHost = new WebHostBuilder()
    .UseKestrel(options => 
         options.Listen(IPAddress.Loopback, 0)) // dynamic port
    .Build();

webHost.Start();

string address = webHost.ServerFeatures
    .Get<IServerAddressesFeature>()
    .Addresses
    .First();
int port = int.Parse(address.Split(':').Last());

webHost.WaitForShutdown();
Wayne Bloss
  • 5,370
  • 7
  • 50
  • 81
Vladimir Panchenko
  • 1,141
  • 2
  • 15
  • 25
  • Instead of using `Console.ReadKey()` use `webHost.WaitForShutdown()` – Preston S Apr 01 '19 at 19:13
  • 1
    You should use `int.Parse(address.Split(':').Last());` because the address could be defined as an IPv6 address – 0BLU Jul 23 '19 at 00:05
  • You can also use `webHost.RunAsync()` instead of `webHost.Start()` if you want to get the default messages printed in your console/output before you get the addresses. – Wayne Bloss Sep 10 '19 at 12:54
3

I was able to do it in the StartUp.cs using the following code:

int Url = new System.Uri(Configuration["urls"]).Port;
3

At least from .Net Core 3 you can inject IServer and get the information.

using System;
using System.Linq;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;

namespace MyApp.Controllers
{
    public class ServerInfoController : Controller
    {
        public ServerInfoController (IServer server)
        {
            var addresses = server.Features.Get<IServerAddressesFeature>()?.Addresses?.ToArray();
        }
    }
}
James Durda
  • 625
  • 6
  • 12
  • This is an incomplete answer .. Unable to resolve service for type 'Microsoft.AspNetCore.Hosting.Server.IServer' – Gabriel Luca Dec 31 '20 at 17:01
  • @GabrielLuca It appears there may be issues with `IServer` not being registered if `WebHost.CreateDefaultBuilder` isn't called. `ConfigureKestrel` does not register the `IServer` but `UseKestrel` and `CreateDefaultBuilder` do. – James Durda Dec 31 '20 at 17:43
  • I called also called WebHost.CreateDefaultBuilder and still not working ... I'll take back my down vote because ... it's strange how M$ changes things and something this simple is hard to .. get .. I can't change my vote unless you change the answer ... it dose not allow me .. – Gabriel Luca Dec 31 '20 at 19:16
  • if you can make it work .. post a small sample it will help .. – Gabriel Luca Dec 31 '20 at 19:18
  • Using net7 with `WebApplication.CreateBuilder(args)` this is working fine. And if you need `IServer` in StartUp, you can get it with `app.Services.GetRequiredService()`. – ArgusMagnus Mar 17 '23 at 06:29
2

I'm able to do it using reflection (ugh!). I've registered an IHostedService and injected IServer. The ListenOptions property on KestrelServerOptions is internal, therefore I need to get to it using reflection. When the hosted service is called I then extract the port using the following code:

var options = ((KestrelServer)server).Options;
var propertyInfo = options.GetType().GetProperty("ListenOptions", BindingFlags.Instance | BindingFlags.NonPublic);
var listenOptions = (List<ListenOptions>)propertyInfo.GetValue(options);
var ipEndPoint = listenOptions.First().IPEndPoint;
var port = ipEndPoint.Port;
g t
  • 7,287
  • 7
  • 50
  • 85
Christo
  • 1,802
  • 4
  • 20
  • 31