Injecting instances within the provider
You can inject registered services into any class that is registered to the IServiceProvider
.
This can be done through property or constructor.
Note
As mentioned above, the dependency and the target class have to be registered in order for the serviceprovider to resolve it.
Injecting through a constructor
Services can be injected from the constructor of the class. This is the preferred approach, because it automatically locks the readonly field in place with the provided service and isn't accessible outside of the class.
public class ClientHandler
{
private readonly DiscordSocketClient _client;
public ClientHandler(DiscordSocketClient client)
{
_client = client;
}
public async Task ConfigureAsync()
{
//...
}
}
Injecting through properties
Injecting through properties is also allowed as follows.
public class ClientHandler
{
public DiscordSocketClient Client { get; set; }
public async Task ConfigureAsync()
{
//...
}
}
Warning
Dependency Injection will not resolve missing services in property injection, and it will not pick a constructor instead. If a publicly accessible property is attempted to be injected and its service is missing, the application will throw an error.
Using the provider itself
You can also access the provider reference itself from injecting it into a class. There are multiple use cases for this:
- Allowing libraries (Like Discord.Net) to access your provider internally.
- Injecting optional dependencies.
- Calling methods on the provider itself if necessary, this is often done for creating scopes.
public class UtilizingProvider
{
private readonly IServiceProvider _provider;
private readonly AnyService _service;
// This service is allowed to be null because it is only populated if the service is actually available in the provider.
private readonly AnyOtherService? _otherService;
// This constructor injects only the service provider,
// and uses it to populate the other dependencies.
public UtilizingProvider(IServiceProvider provider)
{
_provider = provider;
_service = provider.GetRequiredService<AnyService>();
_otherService = provider.GetService<AnyOtherService>();
}
// This constructor injects the service provider, and AnyService,
// making sure that AnyService is not null without having to call GetRequiredService
public UtilizingProvider(IServiceProvider provider, AnyService service)
{
_provider = provider;
_service = service;
_otherService = provider.GetService<AnyOtherService>();
}
}
Note
It is important to keep in mind that the provider will pick the 'biggest' available constructor. If you choose to introduce multiple constructors, keep in mind that services missing from one constructor may have the provider pick another one that is available instead of throwing an exception.