Auto-registration of dependencies with MS DI

182 views Asked by At
    services.AddSingleton<NavigationBarViewModel>();
    services.AddSingleton<FileHandlingViewModel>();
    services.AddSingleton<SchedulingProblemViewModel>();
    ....

    services.AddSingleton<Func<FileHandlingViewModel>>((s) => () => s.GetRequiredService<FileHandlingViewModel>());
    services.AddSingleton<Func<SchedulingProblemViewModel>>((s) => () => s.GetRequiredService<SchedulingProblemViewModel>());
    services.AddSingleton<Func<TimeIntervalsViewModel>>((s) => () => s.GetRequiredService<TimeIntervalsViewModel>());
    ...

I register a bunch of Func as indicated above into MS DI container. I can list the relevant types with reflection. I can auto-register the types, but I also want to auto-register the Funcs with foreach. Any idea for the later?

1

There are 1 answers

0
Istvan Heckl On

It seems auto-registration of factory method can not be done in MS DI. The problem is that we can create the factory method with MakeGenericMethod but this method still needs an explicit cast what we can not use in an auto-registration loop.

Workaround: Use factory class instead of factory method.

public class PageViewModelFactory<TPageViewModel> where TPageViewModel : ViewModelBase
{
    private readonly IServiceProvider services;

    public PageViewModelFactory(IServiceProvider services)
    {
        this.services = services;
    }

    public TPageViewModel Create() => services.GetRequiredService<TPageViewModel>(); // Transient
}

var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
    .Where(t => !t.IsInterface).ToList();
// auto-register all type which implements IPage
types.Where(t => typeof(IPage).IsAssignableFrom(t))
    .ToList().ForEach(t => CreateAndAddClosedType(services, typeof(PageViewModelFactory<>), t));

private static void CreateAndAddClosedType(IServiceCollection services, Type openType, Type? type)
{
    var typeArgs = new Type[] { type! };
    var closedType = openType.MakeGenericType(typeArgs);
    services.AddSingleton(closedType);
}

Storing IServiceProvider in the Factory class seems to be the service locator ani-pattern but MS DI does the same when we register a Func manually. Now we can use PageViewModelFactory<FileHandlingViewModel>.Create instead of Func<FileHandlingViewModel>.