Search code examples
c#unity-container

Is it possible to inject the proper type without constructing or resolving an instance of it in the unity config?


DbContext Registrations

container.RegisterType<DbContext, MobileEntities>(GetLifetime());
container.RegisterType<DbContext, AuthenticationEntities>("AuthDb", GetLifetime());

Generic Repository Registration

container.RegisterType(typeof(IReadOnlyRepository<>), typeof(ReadOnlyRepository<>), GetLifetime());
container.RegisterType(typeof(IReadOnlyRepository<>), typeof(ReadOnlyRepository<>), "ReadOnlyAuth", GetLifetime(), new InjectionConstructor(
    container.Resolve<DbContext>("AuthDb")
));

The above repository takes a DbContext as its only parameter. I have multiple contexts that I want to inject based on the generic parameter provided. Is it possible to inject the proper DbContext type without constructing or resolving an instance of it in the unity config?

container.RegisterType<IUserPermissionService, UserPermissionService>(GetLifetime(), new InjectionConstructor(
    container.Resolve<IReadOnlyRepository<Customer>>("ReadOnlyAuth"),
    container.Resolve<IReadOnlyRepository<VisitPlan>>("ReadOnlyAuth"),
    container.Resolve<IReadOnlyRepository<UserBranch>>("ReadOnlyAuth"),
    container.Resolve<IReadOnlyRepository<UserRoute>>("ReadOnlyAuth"),
    container.Resolve<IReadOnlyRepository<UserDriverNumber>>("ReadOnlyAuth"),
    container.Resolve<IReadOnlyRepository<UserActivity>>("ReadOnlyAuth"),
    container.Resolve<IReadOnlyRepository<UserRole>>("ReadOnlyAuth")
));

Can I configure it so that the Resolve<> calls above aren't executed until the registration they are apart of are resolved? i.e. Can I configure it such that it only executes container.Resolve<DbContext>("AuthDb") when a request to resolve 'ReadOnlyAuth' is made.


Solution

  • You can use ResolvedParameter InjectionMember to indicate that you wish to resolve the value at a later time. A resolver will be created that will use the name and type to obtain the dependency at resolve time.

    container.RegisterType<IUserPermissionService, UserPermissionService>(
        GetLifetime(), 
        new InjectionConstructor(
            new ResolvedParameter<IReadOnlyRepository<Customer>>("ReadOnlyAuth"),
            new ResolvedParameter<IReadOnlyRepository<VisitPlan>>("ReadOnlyAuth"),
            new ResolvedParameter<IReadOnlyRepository<UserBranch>>("ReadOnlyAuth"),
            new ResolvedParameter<IReadOnlyRepository<UserRoute>>("ReadOnlyAuth"),
            new ResolvedParameter<IReadOnlyRepository<UserDriverNumber>>("ReadOnlyAuth"),
            new ResolvedParameter<IReadOnlyRepository<UserActivity>>("ReadOnlyAuth"),
            new ResolvedParameter<IReadOnlyRepository<UserRole>>("ReadOnlyAuth")
        ));
    

    In these cases an InjectionFactory can be used as well:

    container.RegisterType<IUserPermissionService, UserPermissionService>(
        GetLifetime(), 
        new InjectionFactory(c =>
        {
            new UserPermissionService(
                c.Resolve<IReadOnlyRepository<Customer>>("ReadOnlyAuth"),
                c.Resolve<IReadOnlyRepository<VisitPlan>>("ReadOnlyAuth"),
                c.Resolve<IReadOnlyRepository<UserBranch>>("ReadOnlyAuth"),
                c.Resolve<IReadOnlyRepository<UserRoute>>("ReadOnlyAuth"),
                c.Resolve<IReadOnlyRepository<UserDriverNumber>>("ReadOnlyAuth"),
                c.Resolve<IReadOnlyRepository<UserActivity>>("ReadOnlyAuth"),
                c.Resolve<IReadOnlyRepository<UserRole>>("ReadOnlyAuth")
        }));
    

    If you use an injection factory you do get compile time checking to ensure that the constructor arguments are of the correct types.