How to configure Kestrel urls in startup class

12.2k views Asked by At

I am trying to figure out the proper way to modify the URL(s) that kestrel listens on from the Startup class constructor.

Update: In addition to the answer below, I've come to understand that Startup class isn't used to configure Kestrel in the way I had thought. I had thought that Startup would create a single application-wide configuration object that would be located through convention, it is not. As @Tseng points out, the configuration of the Application and Hosting are separate concerns. The linked answer and accepted answer provide working examples.

I spun up a brand new Ubuntu 14 box in Vagrant and installed ASP.NET Core 1.1 according to the current instructions from Microsoft: https://www.microsoft.com/net/core#linuxubuntu

I ran:

  • dotnet new -t web
  • dotnet restore
  • dotnet run

This listens on http://localhost:5000 by default. In Program.cs I can call app.UseUrls("http://*:5001) and this works to change the URL and port.

What I really want is to change the URLs by convention through adding a new JSON setting file in the Startup class, so I followed examples and created a hosting.JSON file with this (note: I've tried "server.urls" and "urls" as the key).

{
  urls: "http://*:5001"
}

In Startup.cs below the default lines for adding the appsettings.json files I added .AddJsonFile("hosting.json", optional: false); (optional: false to make sure it was picking up the file)

public Startup(IHostingEnvironment env)
{
  var builder = new ConfigurationBuilder()
  .SetBasePath(env.ContentRootPath)
  .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
  .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
  .AddJsonFile("hosting.json", optional: false);
  if (env.IsDevelopment())
  {
    // For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709
    builder.AddUserSecrets();
  }

  builder.AddEnvironmentVariables();
  Configuration = builder.Build();
}

I have verified that the setting is there after the configuration builds, but it is not picked up or used when the host is built in the Program.cs

public class Program
{
  public static void Main(string[] args)
  {
    var host = new WebHostBuilder()
    .UseKestrel()
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseIISIntegration()
    .UseStartup<Startup>()
    .Build();

    host.Run();
  }
}

and the application still starts listening on localhost:5000. It is my (likely incorrect) understanding that by having a setting properly named with the correct key the WebHostBuidler should pick it up and use it.

I've seen other examples that basically get rid of the startup class and create the configuration in Program.cs where it can then be passed into a call to UseConfiguration but again my understanding is that using a Startup class should do this by convention.

Essentially I'd like to keep Startup and Program separate, add a hosting.JSON file to the configuration with URLs, and have it picked up and used without needing to call UseUrls, UseConfiguration, etc.

Am I missing something obvious, or trying to do something that is not actually correct?

To explain why this is not a duplicate as per my comment:

  • That post specifically says "launcherSettings is for Visual Studio F5". I am using the command line on a Linux box. Nothing to do with VS.

  • The solution provided in that post moved the configuration build into the main method. I specifically state that I want to build my configuration in the Startup class just like the default "dotnet new -t web" project.

I do not feel this is a duplicate, and am still reviewing the ASP.NET Core source to see if this is possible.

In regards to the correct key:

https://github.com/aspnet/Hosting/blob/b6da89f54cff11474f17486cdc55c2f21f2bbd6b/src/Microsoft.AspNetCore.Hosting.Abstractions/WebHostDefaults.cs

namespace Microsoft.AspNetCore.Hosting
{
  public static class WebHostDefaults
  {
    public static readonly string ApplicationKey = "applicationName";
    public static readonly string StartupAssemblyKey = "startupAssembly";
    public static readonly string DetailedErrorsKey = "detailedErrors";
    public static readonly string EnvironmentKey = "environment";
    public static readonly string WebRootKey = "webroot";
    public static readonly string CaptureStartupErrorsKey = "captureStartupErrors";
    public static readonly string ServerUrlsKey = "urls";
    public static readonly string ContentRootKey = "contentRoot";
  }
}

https://github.com/aspnet/Hosting/blob/80ae7f056c08b740820ee42a7df9eae34541e49e/src/Microsoft.AspNetCore.Hosting/Internal/WebHost.cs

public class WebHost : IWebHost
{
  private static readonly string DeprecatedServerUrlsKey = "server.urls";
1

There are 1 answers

7
Anuraj On BEST ANSWER

In your hosting.json file you should use server.urls instead of urls. And hosting.json file need to added in the program.cs (in the main method) not in startup.

Here is my hosting.json file.

{
  "server.urls": "http://localhost:5010;http://localhost:5012"
}

Here is the Main method.

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddCommandLine(args)
        .AddEnvironmentVariables(prefix: "ASPNETCORE_")
        .AddJsonFile("hosting.json", optional: true)
        .Build();

    var host = new WebHostBuilder()
        .UseConfiguration(config)
        .UseKestrel()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseIISIntegration()
        .UseStartup<Startup>()
        .Build();

    host.Run();
}

And here is the screenshot.

Screenshot of ASP.NET Core app running