C# .NET core将命令行参数从Program.cs传递到Startup.cs

C# .NET core将命令行参数从Program.cs传递到Startup.cs,c#,.net-core,C#,.net Core,我正在尝试配置kestrel,使其在原始模式下在特定端口上运行。但是,要做到这一点,launchsettings.json似乎需要传递命令行args,因为没有直接向上选项,它总是在端口5000上运行,如果您有需要运行的api和网站,这显然会发生冲突 因此,我将CommandLine包添加到我的站点,您确实可以在startup.cs文件中使用builder.AddCommandLine() 问题是如何将参数从program.cs获取到Startup.cs,或者查找它们而不是静态变量 如果无法获取a

我正在尝试配置kestrel,使其在原始模式下在特定端口上运行。但是,要做到这一点,launchsettings.json似乎需要传递命令行args,因为没有直接向上选项,它总是在端口5000上运行,如果您有需要运行的api和网站,这显然会发生冲突

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

问题是如何将参数从program.cs获取到Startup.cs,或者查找它们而不是静态变量

如果无法获取args,扩展方法就会变得毫无意义


有更好的方法吗?

Kestrel可以通过多种方式配置为在不同的端口上侦听。这些方法都不需要出现在
Startup
类中,而是出现在
Program
类的
Main
方法中。使用
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();
}

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

UPDATE

事实上,我找到了一个似乎更优雅的解决方案:

  • 在程序中将命令行参数解析为
    IConfigurationRoot
    (使用CommandLineApplication、好文章和示例)
  • 只需通过DI容器将此
    IConfigurationRoot
    传递到
    Startup
  • 像这样:

    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
        }
    }
    
    旧答案

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

    公共静态IWebHost BuildWebHost(字符串[]args)
    {
    //加载配置并附加命令行参数
    var config=new ConfigurationBuilder()
    .SetBasePath(Path.GetDirectoryName(Assembly.GetExecutionGassembly().Location))
    .AddJsonFile(“configuration.json”)
    .AddCommandLine(args)
    .Build();
    //将配置传递给启动实例
    var startup=新启动(配置);
    //而不是使用UseStartup()
    //向服务注册启动
    返回新的WebHostBuilder()
    .UseKestrel()
    .UseSetting(“applicationName”,“Your.Assembly.Name”)
    .UseConfiguration(配置)
    .ConfigureServices(服务=>services.AddSingleton(启动))
    .Build();
    }
    
    需要注意的几点是:

    • 通过这样做,启动程序应该实现
      IStartup
      ,它将参数中的
      Configure
      方法限制为仅
      Configure(IApplicationBuilder应用程序)
      而不是完整的
      Configure(IApplicationBuilder应用程序、IHostingEnvironment环境、ILoggerFactory、IApplicationLifetime生命周期)
    • 出于某种原因,您需要手动指定
      applicationName
      参数,如我的示例所示。我正在
      2.0.0-preview1-final

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

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

        公共类启动
        {
        公共启动(IHostingEnvironment环境)
        {
        var args=Environment.GetCommandLineArgs().Skip(1.ToArray();
        var builder=new ConfigurationBuilder();
        builder.AddCommandLine(args);
        Configuration=builder.Build();
        }
        }
        
        您是否尝试使用命令行上指定的端口运行应用程序,像
        dotnet运行myproject--port 3333
        ?是的,或者让vs.Net或vs.code指定一个唯一的端口,这样两个站点可以同时运行。我的问题是,现在启动与startup.cs分离,注入用于测试的内容在正确意义上不再可能,因为配置创建是在main中进行的,而不是在main中启动。另外,使用URL似乎也不错,但我希望这不会影响azure部署?如果使用AddCommandLine选项,它不应该干扰azure部署,因为只有在命令行上指定了端口,它才会更改端口。确定,但这仍然会将配置创建与startup.cs和di解耦。@DanielGrim他需要将命令行参数传递给startup,您的解决方案不会解决这个问题。Yuk,但ok。这些东西应该在vs.net 2017中简单地实现和设置。但不,这是一个黑客。
        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
            }
        }
        
        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();
        }
        
        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();
        }