36

I have arguments passed in via the command-line

private static int Main(string[] args)
{
    const string PORT = "12345"    ;

    var listeningUrl = $"http://localhost:{PORT}";

    var builder = new WebHostBuilder()
        .UseStartup<Startup>()
        .UseKestrel()
        .UseUrls(listeningUrl);

    var host = builder.Build();
    WriteLine($"Running on {PORT}");
    host.Run();

    return 0;
}

One of these arguments is a logging output directory. How do I get this value into my Startup class so I can write out to this directory when I receive a request?

I'd like to avoid using a static class. Would a service that supplies the value be the right way? If so, how do I get services injected into my middleware?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
BanksySan
  • 27,362
  • 33
  • 117
  • 216

5 Answers5

41

You should be able to use the AddCommandLine() extension. First install the Nuget package Microsoft.Extensions.Configuration.CommandLine and ensure you have the correct import:

using Microsoft.Extensions.Configuration;

Now update your Main method to include the new config:

var config = new ConfigurationBuilder()
    .AddJsonFile("hosting.json", optional: true) //this is not needed, but could be useful
    .AddCommandLine(args)
    .Build();

var builder = new WebHostBuilder()
    .UseConfiguration(config)  //<-- Add this
    .UseStartup<Startup>()
    .UseKestrel()
    .UseUrls(listeningUrl);

Now you treat the command line options as configuration:

dotnet run /MySetting:SomeValue=123

And read in code:

var someValue = Configuration.GetValue<int>("MySetting:SomeValue");
DavidG
  • 113,891
  • 12
  • 217
  • 223
25

Dotnet Core 2

You don't need most of the code as in dotnet core 1.0 to achieve this. AddCommandLinearguments are automatically injected when you BuildWebHost using the following syntax

Step 1.

public static IWebHost BuildWebHost(string[] args)
{
    return WebHost.CreateDefaultBuilder(args)
                  .UseStartup<Startup>()
                  .Build();
}

Step 2. Inject configurations to Startup.cs using DI using the following code

public class Startup
{
    private readonly IConfiguration Configuration;

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    ...

}

Step 3. Access your arguments using configurations object.

var seed = Configuration.GetValue<bool>("seed");
Console.WriteLine($"seed: {seed}");

Step 4. Start application with arguments

dotnet run seed=True
phoenix
  • 7,988
  • 6
  • 39
  • 45
CuriousGuy
  • 3,818
  • 4
  • 24
  • 28
12

ASP.NET Core 2 answer:

Change the default Program.cs to be:

using System;
using System.IO;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.SetBasePath(Directory.GetCurrentDirectory());
                config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                      .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true);
                config.AddEnvironmentVariables();
                config.AddCommandLine(args);
            })
            .UseStartup<Startup>()
            .Build();
}

I removed other bits just to make the configuration explanation easier.

Note the .AddCommandLine(args) line in the configuration builder.

Unlike @BanksySan's answer you DON'T need to create a static property, instead let DI inject the IConfiguration into the startup class.

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    private IConfiguration Configuration { get; }

You can now use the configuration entries from any of the config providers, file, env variables and commandline.

Example:

dotnet run --seed true

    public void Configure(IApplicationBuilder app)
    {
        app.UseExceptionHandler("/Home/Error");

        var seed = Configuration.GetValue<bool>("seed");
        if (seed)
            SeedData.Initialize(app);

        app.UseStaticFiles();
        app.UseMvcWithDefaultRoute();
    }

Hope this helps someone further.

Allan
  • 673
  • 6
  • 14
  • I was able to do the same thing on my Worker.cs class too for when hosting ASP.NET Core in a Windows Service - adding a constructor that takes in the IConfiguration object worked there too. – Ciaran Gallagher Jun 17 '20 at 08:48
6

DavidG's answer is correct, but there were still some pieces of the puzzle missing for me.

There are two Nuget packages you need:

  1. Microsoft.Extensions.Configuration.Binder
  2. Microsoft.Extensions.Configuration.CommandLine

Because we want the command line arguments, we need to create the configuration in the Main(string[]).

using Microsoft.Extensions.Configuration;

class Program
{
    private static int Main(string[] args)
    {
        const string PORT = "12345";

        var listeningUrl = $"http://localhost:{PORT}";
        var configuration = new ConfigurationBuilder()
                            .AddCommandLine(args)
                            .Build();
        // Set the `static` `Configuration` property on the `Startup` class.
        Startup.Configuration = configuration;

        var builder = new WebHostBuilder()
            .UseStartup<Startup>()
            .UseKestrel()
            .UseSetting("Message", "Hello World")
            .UseUrls(listeningUrl);

        var host = builder.Build();
        WriteLine($"Running on {listeningUrl}");
        host.Run();

        return SUCCESS_EXIT_CODE;
    }
}

The Startup class is:

using Microsoft.Extensions.Configuration;

public class Startup
{
    public static IConfiguration Configuration { get; set; }


    public void Configure(IApplicationBuilder app)
    {
        foreach (var c in Configuration.AsEnumerable())
            Console.WriteLine($"{c.Key,-15}:{c.Value}");
    }
}

Is the command argument are --port 6000 outputDirectory C:\Temp then this will output:

port            :6000
outputDirectory :C:\Temp
BanksySan
  • 27,362
  • 33
  • 117
  • 216
  • Also in Microsoft Docs: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?tabs=basicconfiguration#setup-and-use-the-commandline-configuration-provider – Corwin Feb 13 '18 at 17:55
5

If you just need the raw command line arguments passed to the process, or you don't want to add them to the configuration, you can still use the following:

Environment.GetCommandLineArgs();
Professor of programming
  • 2,978
  • 3
  • 30
  • 48