.NET core Pass Commandline Args to Startup.cs from Program.cs

前端 未结 3 454
被撕碎了的回忆
被撕碎了的回忆 2021-01-04 22:44

I\'m trying to configure kestrel so that when it\'s in it\'s raw mode it runs on a specific port. However to do so it appears that the launchsettings.json needs to pass comm

相关标签:
3条回答
  • 2021-01-04 23:10

    UPDATE

    I actually found what seems more elegant solution:

    1. Parse command line arguments into IConfigurationRoot in Program (using CommandLineApplication, good article & examples here)
    2. Just pass this IConfigurationRoot to Startup via DI container.

    Like so:

    public static IWebHost BuildWebHost(string[] args)
    {
        var configuration = LoadConfiguration(args);
    
        // Use Startup as always, register IConfigurationRoot to services
        return new WebHostBuilder()
            .UseKestrel()
            .UseConfiguration(configuration)
            .ConfigureServices(s => s.AddSingleton<IConfigurationRoot>(configuration))
            .UseStartup<Startup>()
            .Build();
    }
    
    public class Startup
    {
        public Startup(IConfigurationRoot configuration)
        {
            // You get configuration in Startup constructor or wherever you need
        }
    }
    

    Example implementation of LoadConfiguration, which parses args and builds IConfigurationRoot (in this example configuration file name can be overridden in command line arguments):

    private static IConfigurationRoot LoadConfiguration(string[] args)
    {
        var configurationFileName = "configuration.json";
    
        var cla = new CommandLineApplication(throwOnUnexpectedArg: true);
    
        var configFileOption = cla.Option("--config <configuration_filename>", "File name of configuration", CommandOptionType.SingleValue);
    
        cla.OnExecute(() =>
        {
            if (configFileOption.HasValue())
                configurationFileName = configFileOption.Value();
    
            return 0;
        });
    
        cla.Execute(args);
    
        return new ConfigurationBuilder()
            .SetBasePath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
            .AddJsonFile(configurationFileName, optional: false, reloadOnChange: true)
            .AddCommandLine(args)
            .Build();
    }
    

    OLD ANSWER

    You can instantiate Startup class by yourself and pass it as instances to WebHostBuilder. It is somewhat not so elegant, but doable. From here.

    public static IWebHost BuildWebHost(string[] args)
    {
        // Load configuration and append command line args
        var config = new ConfigurationBuilder()
            .SetBasePath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
            .AddJsonFile("configuration.json")
            .AddCommandLine(args)
            .Build();
    
        // pass config to Startup instance
        var startup = new Startup(config);
    
        // Instead of using UseStartup<Startup>()
        // Register startup to services
        return new WebHostBuilder()
            .UseKestrel()
            .UseSetting("applicationName", "Your.Assembly.Name")
            .UseConfiguration(config)
            .ConfigureServices(services => services.AddSingleton<IStartup>(startup))
            .Build();
    }
    

    Couple of caveats are:

    • by doing so, Startup should implement IStartup which is limited for Configure method in parameters to only Configure(IApplicationBuilder app) instead of full Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime lifetime)
    • For some reason, you need to specify applicationName parameter manually as in my example. I'm testing this on 2.0.0-preview1-final
    0 讨论(0)
  • 2021-01-04 23:19

    A simple solution is to access the command line arguments through the Environment.GetCommandLineArgs method.

    You only need to make sure that you remove the first argument, which is the executable name:

    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var args = Environment.GetCommandLineArgs().Skip(1).ToArray();
            var builder = new ConfigurationBuilder();
            builder.AddCommandLine(args);
    
            Configuration = builder.Build();
        }
    }
    
    0 讨论(0)
  • 2021-01-04 23:25

    Kestrel can be configured to listen on a different port in several ways. None of these methods need to happen in the Startup class, but rather in the Main method of the Program class. Using the AddCommandLine extension method is one of them. To use that, modify your Program.cs file's Main method to look something like this:

    public static void Main(string[] args)
    {
        var config = new ConfigurationBuilder()
            .AddCommandLine(args)
            .Build();
    
        var host = new WebHostBuilder()
                    .UseKestrel()
                    .UseConfiguration(config)
                    .UseStartup<Startup>()
                    .Build();
        host.Run();
    }
    

    Then, run the application with dotnet run --server.urls http://*:<yourport>, replacing <yourport> with the actual port number that you want it to run on. The * makes it listen on all available IP addresses, if you want to listen on a specific address then you need to specify it there instead of the *.

    Another option for changing the port is to use the .UseUrls method to hard-code the port and address. For example:

    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
                    .UseKestrel()
                    .UseUrls("http://*:8080")
                    .UseStartup<Startup>()
                    .Build();
        host.Run();
    }
    

    This example will make your application listen on port 8080 on all available IP addresses.

    0 讨论(0)
提交回复
热议问题