10

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";
Steve
  • 596
  • 2
  • 7
  • 20
  • 1
    Possible duplicate of [Can't set the port for Net.Core application in launchSettings.JSON](http://stackoverflow.com/questions/40550798/cant-set-the-port-for-net-core-application-in-launchsettings-json) – Tseng Jan 07 '17 at 00:43
  • The the correct string is btw. `server.urls`, but I'm not sure anymore if it will just work in startup and if thats already too late. With the linked one it will work for sure (reading hosting in main method and pass it to the web builder) – Tseng Jan 07 '17 at 00:43
  • Read the answer, it covers exactly the same stuff and it handles about setting the port for kestrel. The poster was just initially confused by the launcherSettings – Tseng Jan 07 '17 at 02:06
  • Regardless, the question states I do not want to move the configuration out of Startup very specifically. If it is 100% with certainty not possible, then that is the answer, but this is a different question. – Steve Jan 07 '17 at 02:07
  • @Tseng I've now emboldened the specific parts of my question that make it different, I've added explanation, I've shown that I have been researching the source, I've stated that I have tried these approaches. I'm not sure how I can be more clear that this is a different question even if the outcome I am after is the same. I want to approach it in a different way. You state "I'm not sure anymore if it will just work in startup and if thats already too late" That is exactly the question I am trying to get an answer to. – Steve Jan 07 '17 at 02:15

1 Answers1

6

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

Anuraj
  • 18,859
  • 7
  • 53
  • 79
  • Thank you, I am aware that this technique works, but as per my original post, I am looking for a way to maintain the separation of Startup and Program. I want keep configuration in Startup as it is in the default project created with dotnet new -t web. I don't understand why configuring Urls would necessitate moving the configuration into the Program or Main class. – Steve Jan 07 '17 at 01:46
  • 2
    @Steve: Because both configurations are unrelated. One is for your application the other is just hosting related. They just happen to use the same configuration framework/library to achieve it. You can also use command line or environment variables to set the port, all the ways are in the linked **answer** (not the post) – Tseng Jan 07 '17 at 02:10
  • 1
    @Tseng Thanks! I had the mistaken belief that Startup could be used to create a global configuration instance that would be located through convention by the rest of the application. Spending the last hour in the source with this comment in mind has provided a deeper understanding. Problem is that no one actually said "you can't do that the way you think" and instead offered alternate solutions that didn't address my question. Could you turn your comment into an answer I can accept? – Steve Jan 07 '17 at 03:41
  • @Steve: Just accept this one, my answer linked in the comment is already there for other users. We're not here for just collecting Reputation ;) – Tseng Jan 07 '17 at 04:01
  • @Tseng - Done, also edited my post to explain my mistake in case anyone else heads down the same misguided path I was on! – Steve Jan 07 '17 at 04:51
  • 2
    `.AddCommandLine(args)` should be after `.AddJsonFile("hosting.json", optional: true)`, otherwise you cannot override the config with the console args. – Morten Christiansen Feb 02 '17 at 10:23
  • The configuration option seems to be just "urls" now. – lex82 May 05 '17 at 07:14