.NET核心从Program.cs传递命令行Args到Startup.cs

Jam*_*ock 9 c# .net-core

我正在尝试配置kestrel,以便当它处于原始模式时,它会在特定端口上运行.但是为了这样做,似乎launchsettings.json需要通过命令行参数来执行此操作,因为没有直接选项,它总是在端口5000上运行,如果你有一个需要运行的api和一个网站,这显然会发生冲突.

所以我将CommandLine包添加到我的站点,你确实可以在startup.cs文件中使用builder.AddCommandLine().

问题是如何从program.cs到Startup.cs获取args或者查看静态变量以外的其他方法.

如果你不能得到args,那种扩展方法会毫无意义.

有没有更好的方法呢?

Alg*_*das 6

UPDATE

我实际上找到了更优雅的解决方案:

  1. 将命令行参数解析到IConfigurationRootProgram中(使用CommandLineApplication,这里有好文章和示例)
  2. 只需将其传递IConfigurationRootStartupDI容器即可.

像这样:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

LoadConfiguration的示例实现,它解析args和构建IConfigurationRoot(在此示例中,配置文件名可以在命令行参数中重写):

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();
}
Run Code Online (Sandbox Code Playgroud)

老答复

您可以自己实例化Startup类,并将其作为实例传递给WebHostBuilder.它有点不那么优雅,但可行.从这里开始.

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();
}
Run Code Online (Sandbox Code Playgroud)

几点需要注意:

  • 通过这样做,Startup应该实现IStartup哪些仅限Configure于参数中的方法Configure(IApplicationBuilder app)而不是完整Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime lifetime)
  • 出于某种原因,您需要applicationName手动指定参数,如我的示例所示.我正在测试这个2.0.0-preview1-final


Dan*_*rim 5

可以将Kestrel配置为以多种方式侦听不同的端口.这些方法都不需要在Startup类中发生,而是在类的Main方法中发生Program.使用AddCommandLine扩展方法就是其中之一.要使用它,请修改Program.cs文件的Main方法,如下所示:

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();
}
Run Code Online (Sandbox Code Playgroud)

然后,运行应用程序dotnet run --server.urls http://*:<yourport>,替换<yourport>为您希望它运行的实际端口号.将*使得它侦听所有可用的IP地址,如果你想监听特定的地址,那么你需要有指定的,而不是它*.

更改端口的另一个选项是使用该.UseUrls方法对端口和地址进行硬编码.例如:

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

此示例将使您的应用程序8080在所有可用IP地址上侦听端口.


Sam*_*iar 5

一个简单的解决方案是通过Environment.GetCommandLineArgs方法访问命令行参数.

您只需要确保删除第一个参数,即可执行文件名:

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var args = Environment.GetCommandLineArgs().Skip(1).ToArray();
        var builder = new ConfigurationBuilder();
        builder.AddCommandLine(args);

        Configuration = builder.Build();
    }
}
Run Code Online (Sandbox Code Playgroud)