Dependency Injection
CommandLineUtils allow you to use dependency injection to inject dependencies into command constructors at runtime. This gives you the ability to avoid tight coupling between the commands and the services which they depend on. CommandLineUtils has a standard set of services which are available to inject and also allow you to register and inject your own services.
Using dependency injection
To inject services into a command constructor, you need to specify the services to be injected as parameters for the public constructor of the command.
In the example below, the IConsole
implementation is injected into the constructor and stored in a field named _console
. Later in the program, this is used to write output to the console:
[Command(Name = "di", Description = "Dependency Injection sample project")]
[HelpOption]
class Program
{
private readonly IConsole _console;
static Task<int> Main(string[] args) => CommandLineApplication.ExecuteAsync<Program>(args);
public Program(IConsole console)
{
_console = console;
}
private int OnExecute()
{
_console.WriteLine("Hello from your first application");
return 0;
}
}
Using the standard services
CommandLineApplication makes a number of services available by default for injecting into your command constructors. There are the standard services which you can inject:
Service | Description |
---|---|
CommandLineApplication |
Injects the CommandLineApplication instance. |
IConsole |
Injects the IConsole implementation. |
IEnumerable<CommandOption> |
Injects the definitions for the options passed to the command. |
IEnumerable<CommandArgument> |
Injects the definitions for the arguments passed to the command. |
CommandLineContext |
Injects the CommandLineContext which contains information abount the execution context of the command. |
IServiceProvider |
... |
Command parent type | When using sub-commands, you can inject the type of the parent command into the constructor for a sub-command. |
Using your own services
You can register your own services by using the ConstructorInjectionConvention and making use of the Microsoft.Extensions.DependencyInjection
NuGet package to contruct services.
In the example below, we have defined a service named IMyService
with a single method named Invoke
:
interface IMyService
{
void Invoke();
}
The implementation of this service is done in MyServiceImplementation
, which will write a string to the console. Also, note that an instance of IConsole
is injected into the MyServiceImplementation
constructor.
class MyServiceImplementation : IMyService
{
private readonly IConsole _console;
public MyServiceImplementation(IConsole console)
{
_console = console;
}
public void Invoke()
{
_console.WriteLine("Hello dependency injection!");
}
}
You can register your own services by creating an instance of ServiceCollection
and adding the services to the collection. A service provider is then created by calling the BuildServiceProvider
method:
var services = new ServiceCollection()
.AddSingleton<IMyService, MyServiceImplementation>()
.AddSingleton<IConsole>(PhysicalConsole.Singleton)
.BuildServiceProvider();
Note
Take note that standard services which need to be injected into your custom services, such as IConsole
which needs to be injected into the MyServiceImplementation
constructor, needs to be added to the service collection as well.
Next, you can call add the constructor injection convention by calling UseConstructorInjection
, passing the service provider which was previously created.
var app = new CommandLineApplication<Program>();
app.Conventions
.UseDefaultConventions()
.UseConstructorInjection(services);
Below is the full source code for the custom services example. Notice that instance of IMyService
will be injected into the Program
constructor thanks to the dependency injection.
[Command(Name = "di", Description = "Dependency Injection sample project")]
[HelpOption]
class Program
{
public static int Main(string[] args)
{
var services = new ServiceCollection()
.AddSingleton<IMyService, MyServiceImplementation>()
.AddSingleton<IConsole>(PhysicalConsole.Singleton)
.BuildServiceProvider();
var app = new CommandLineApplication<Program>();
app.Conventions
.UseDefaultConventions()
.UseConstructorInjection(services);
return app.Execute(args);
}
private readonly IMyService _myService;
public Program(IMyService myService)
{
_myService = myService;
}
private void OnExecute()
{
_myService.Invoke();
}
}
Using Generic Host
See Integration with Generic Host for details on using Generic Host and dependency injection.