.net.net-coreconsole-applicationihostedservice

How can I access the command line arguments in a console application using IHostedService?


I can not figure out how to access the command line args in my ConsoleHostedService implementation class. I see in the sources CreateDefaultBuilder(args) somehow adds it to the configuration... named Args...

Having the main program:

internal sealed class Program
{
    private static async Task Main(string[] args)
    {
        await Host.CreateDefaultBuilder(args)
            .UseContentRoot(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
            .ConfigureServices((context, services) =>
            {
                services.AddHostedService<ConsoleHostedService>();
            })
            .RunConsoleAsync();
    }
}

and the hosted service:

internal sealed class ConsoleHostedService : IHostedService
{
    public ConsoleHostedService(
        IHostApplicationLifetime appLifetime,
        IServiceProvider serviceProvider)
    {
        //...
    }
}

Solution

  • I don't believe there's a built-in DI method to get command-line arguments - but probably the reason that handling command-line arguments is the responsibility of your host application and that should be passing host/environment information in via IConfiguration and IOptions etc.

    Anyway, just define your own injectables:

    public interface IEntrypointInfo
    {
        String CommandLine { get; }
    
        IReadOnlyList<String> CommandLineArgs { get; }
    
        // Default interface implementation, requires C# 8.0 or later:
        Boolean HasFlag( String flagName )
        {
            return this.CommandLineArgs.Any( a => ( "-" + a ) == flagName || ( "/" + a ) == flagName );
        }
    }
    
    /// <summary>Implements <see cref="IEntrypointInfo"/> by exposing data provided by <see cref="System.Environment"/>.</summary>
    public class SystemEnvironmentEntrypointInfo : IEntrypointInfo
    {
        public String CommandLine => System.Environment.CommandLine;
    
        public IReadOnlyList<String> CommandLineArgs => System.Environment.GetCommandLineArgs();
    }
    
    /// <summary>Implements <see cref="IEntrypointInfo"/> by exposing provided data.</summary>
    public class SimpleEntrypointInfo : IEntrypointInfo
    {
        public SimpleEntrypointInfo( String commandLine, String[] commandLineArgs )
        {
            this.CommandLine = commandLine ?? throw new ArgumentNullException(nameof(commandLine));
            this.CommandLineArgs = commandLineArgs ?? throw new ArgumentNullException(nameof(commandLineArgs));
        }
    
        public String CommandLine { get; }
    
        public IReadOnlyList<String> CommandLineArgs { get; }
    }
    
    //
    
    public static class Program
    {
        public static async Task Main( String[] args )
        {
            await Host.CreateDefaultBuilder( args )
                .UseContentRoot(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
                .ConfigureServices((context, services) =>
                {
                    services.AddHostedService<ConsoleHostedService>();
                    services.AddSingleton<IEntrypointInfo,SystemEnvironmentEntrypointInfo>()
                })
                .RunConsoleAsync();
        }
    

    For automated unit and integration tests, use SimpleEntrypointInfo.