Integration with Generic Host
The McMaster.Extensions.Hosting.CommandLine package provides support for integrating command line parsing with .NET's generic host.
Get started
To get started, install the McMaster.Extensions.Hosting.CommandLine and Microsoft.Extensions.Hosting packages.
The main usage for generic host is RunCommandLineApplicationAsync<TApp>(args)
, where TApp
is a class
which will be bound to command line arguments and options using attributes and CommandLineApplication.Execute<T>
.
Sample
This minimal sample shows how to take advantage of generic host features, such as IHostingEnvironment
,
as well as command line parsing options with this library.
using System;
using System.Threading.Tasks;
using McMaster.Extensions.CommandLineUtils;
using Microsoft.Extensions.Hosting;
class Program
{
static Task<int> Main(string[] args)
=> new HostBuilder()
.RunCommandLineApplicationAsync<Program>(args);
[Option]
public int Port { get; } = 8080;
private IHostEnvironment _env;
public Program(IHostEnvironment env)
{
_env = env;
}
private void OnExecute()
{
Console.WriteLine($"Starting on port {Port}, env = {_env.EnvironmentName}");
}
}
Dependency injection
Generic host integration allows you to use the most current DI configuration approach indicated by the aspnet project. The basic approach starts by creating the builder:
return await new HostBuilder()
Then you can configure your features:
.ConfigureLogging((context, builder) =>
{
builder.AddConsole();
})
.ConfigureServices((context, services) =>
{
services.AddSingleton<IGreeter, Greeter>()
.AddSingleton<IConsole>(PhysicalConsole.Singleton);
})
And finally, run your program:
.RunCommandLineApplicationAsync<Program>(args);
Below is the full source code for the generic host services example. Notice that instance of IGreeter
will be injected into the Program
constructor thanks to the dependency injection.
using System;
using System.Threading;
using System.Threading.Tasks;
using McMaster.Extensions.CommandLineUtils;
using McMaster.Extensions.Hosting.CommandLine;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace CustomServices
{
#region Program
[Command(Name = "di", Description = "Dependency Injection sample project")]
class Program
{
[Argument(0, Description = "your name")]
private string Name { get; } = "dependency injection";
[Option("-l|--language", Description = "your desired language")]
[AllowedValues("english", "spanish", IgnoreCase = true)]
public string Language { get; } = "english";
public static async Task<int> Main(string[] args)
{
return await new HostBuilder()
.ConfigureLogging((context, builder) =>
{
builder.AddConsole();
})
.ConfigureServices((context, services) =>
{
services.AddSingleton<IGreeter, Greeter>()
.AddSingleton<IConsole>(PhysicalConsole.Singleton);
})
.RunCommandLineApplicationAsync<Program>(args);
}
private readonly ILogger<Program> _logger;
private readonly IGreeter _greeter;
public Program(ILogger<Program> logger, IGreeter greeter)
{
_logger = logger;
_greeter = greeter;
_logger.LogInformation("Constructed!");
}
private void OnExecute()
{
_greeter.Greet(Name, Language);
}
}
#endregion
#region IGreeter
interface IGreeter
{
void Greet(string name, string language);
}
#endregion
#region Greeter
class Greeter : IGreeter
{
private readonly IConsole _console;
private readonly ILogger<Greeter> _logger;
public Greeter(ILogger<Greeter> logger,
IConsole console)
{
_logger = logger;
_console = console;
_logger.LogInformation("Constructed!");
}
public void Greet(string name, string language = "english")
{
string greeting;
switch (language)
{
case "english": greeting = "Hello {0}"; break;
case "spanish": greeting = "Hola {0}"; break;
default: throw new InvalidOperationException("validation should have caught this");
}
_console.WriteLine(greeting, name);
}
}
#endregion
}