In this post, Rick Strahl explores different techniques to retrieve ASP.NET Core application hosting URLs at startup and during requests, providing code samples and practical advice.

Getting the ASP.NET Core Server Hosting URLs at Startup and in Requests

Author: Rick Strahl Published: September 3, 2024 — Hood River, Oregon


Retrieving the hosting URLs for an ASP.NET Core application is a deceptively tricky task. There are numerous ways to set the addresses, but not a single dedicated location to query them reliably. Depending on whether you need the URLs on startup or inside a request, you’ll need to follow different approaches.

Introduction

Rick recounts a client scenario where an ASP.NET Core application running in IIS wouldn’t start on a known port. The client had altered the default port programmatically, and the hosting URL was not easily discoverable. This challenge underpins the necessity for a robust approach to extract the actual startup URLs.

Common Setup Methods

  • Default Port: Sometimes defaults to 5000
  • Command Line/Env Variables: --urls "<urlList>" or --https_ports can override, unless explicit overrides exist in code
  • Programmatic Assignment: URLs set in code can supersede other settings

See Andrew Lock’s post for 8 ways to set hosting URLs

The Challenge: Getting URLs Reliably at Runtime

While setting the hosting address is well documented, retrieving the actual addresses in use is less straightforward. An ideal scenario is displaying these addresses in a startup banner, useful for both debugging and development purposes.

Typical (but unreliable) approach:

// DON'T USE THIS - works only if URLs assigned via config or command line
var urls = builder.WebHost.GetSetting(WebHostDefaults.ServerUrlsKey)?.Replace(";", " ");

This method doesn’t account for programmatic URL assignments or defaults, and is not always reliable unless the URLs are set via config, environment variables, or command line switches.

The Reliable Way: After the Server has Started

The correct strategy is to query app.Urls, but only after the server has started using app.Start(). Avoid app.Run() if you wish to capture the URLs programmatically.

Example Startup Banner in program.cs

// At the bottom of program.cs
// Replace app.Run() with:
app.Start();

Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine($@"--------------------------------- West Wind Web Store v{wsApp.Version} ---------------------------------");
Console.ResetColor();

var urlList = app.Urls;
string urls = string.Join(" ", urlList);

Console.Write(" Urls: ");
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine(urls, ConsoleColor.DarkCyan);
Console.ResetColor();

Console.WriteLine($" Runtime: {RuntimeInformation.FrameworkDescription} - {builder.Environment.EnvironmentName}");
Console.WriteLine($"Platform: {RuntimeInformation.OSDescription} ({RuntimeInformation.OSArchitecture})");
Console.WriteLine();

app.WaitForShutdown();

Key points:

  • Use app.Urls after app.Start().
  • Present information as a startup banner for clarity during development or debugging.

Retrieving Host URLs Within an HTTP Request

URLs can also be obtained at runtime within a request by leveraging dependency injection to access IServer and IServerAddressesFeature:

public object SystemInfo([FromServices] IServer server) {
    var addresses = server.Features.Get<IServerAddressesFeature>()?.Addresses;
    // process addresses...
}

Alternatively, this pattern also works in startup code after app.Start():

var server = app.Services.GetService(typeof(IServer)) as IServer;
var addrs = server.Features.Get<IServerAddressesFeature>()?.Addresses;

While both app.Urls and IServerAddressesFeature can be used, app.Urls is simpler if accessed post-startup.

Using .NET Logging to Reveal Hosting URLs

ASP.NET Core conveniently outputs listening ports in the debug log, given that:

  • Logging is enabled to Information level on the Microsoft.Hosting.Lifetime category
  • You’re running in the Development environment, or have the right log level in production via appsettings.json:
$env:ASPNETCORE_ENVIRONMENT = "Development"
dotnet run

Or configure explicitly in appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft": "Error",
      "Microsoft.Hosting.Lifetime": "Information" // Enables port log
    }
  }
}

Note: This method is often disabled in production for performance/security reasons.

Summary

  • Multiple mechanisms exist to set hosting URLs; reliably retrieving the ones in use requires care
  • Using app.Urls after app.Start(), or extracting IServerAddressesFeature via DI, are robust methods
  • Logging can provide this info during development but is less reliable in production

References


Comments/Discussion Highlights:

  • The role of structured logging and configuration is highlighted in the comments, with pros and cons mentioned regarding production use.

This post was created and published with the Markdown Monster Editor

This post appeared first on “Rick Strahl’s Blog”. Read the entire article here