Reputation: 3750
What would be the simplest way to support attribute-based setting reference resolving in ASP.NET Core DI? I would like to make something like this to read the config value:
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
public WeatherForecastController(
[Setting("Logging:LogLevel:Microsoft")] string logLevel)
{
…
When appsettings.json
looks like:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
…
Any ideas how to approach it? I would like it to work for services as well.
Upvotes: 1
Views: 226
Reputation: 172696
Technically, it is possible to achieve this with MS.DI, but it's pretty hard to do so and, as Dmitry mentioned, you will have more luck with mature DI Containers, such as Autofac or Simple Injector.
If you really want to keep using MS.DI, here's some code that would get you started:
var settingDescriptors = (
from descriptor in services
let type = descriptor.ImplementationType
where type != null && !type.IsGenericTypeDefinition
where type.GetConstructors().Single().GetParameters()
.Any(p => p.GetCustomAttribute<SettingAttribute>() != null)
select descriptor)
.ToArray();
foreach (var descriptor in settingDescriptors)
{
services.Remove(descriptor);
object[] settings = // TODO: Determine settings from parameters here
services.Add(new ServiceDescriptor(
descriptor.ServiceType,
c => ActivatorUtilities.CreateInstance(
c,
descriptor.ImplementationType,
settings),
descriptor.Lifetime));
}
What this code does is iterate over the service collection and replace all registrations for an implementation that has a constructor argument which is marked with the SettingAttribute
. That registration is replaced with a registration that uses a factory delegate which asks the DI Container to create an instance, while supplying one or multiple objects (the settings) to it. In other words, it enables Auto-Wiring while manually supplying objects.
What this means is that, to some degree, this is possible with MS.DI, but... there are some serious limitations you should take into consideration:
ActivatorUtilities.CreateInstance
blinds the DI system. Where MS.DI contains checks to prevent circular dependencies, the use of ActivatorUtilities.CreateInstance
will lead to hard to debug stack overflow exceptions in case of a circular dependency.Upvotes: 1