Register generic types in SimpleInjector Version 3

2019-08-01 04:39发布

I've been following the very helpful answer here to organise my unit of work and repositories dynamically using SimpleInjector DI.

Using the test service below:

public class TestService
{
    public TestService(IRepository<Call> calls){}       
}

In the controller:

public class TestingController : Controller
{

    private readonly IUnitOfWork _unitOfWork ;

    public TestingController(IUnitOfWork unitOfWork, TestService testService)
    {
        _unitOfWork = unitOfWork;
    }
}

And the bootstrapper:

public static class BootStrapper
{
    public static void ConfigureWeb(Container container)
    {
        container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
                    container.Options.ConstructorResolutionBehavior = new GreediestConstructorBehavior();


        container.Register<DbContext, OCISContext>(Lifestyle.Scoped);
        container.Register<ApplicationUserManager>(Lifestyle.Scoped);
        container.Register<ApplicationSignInManager>(Lifestyle.Scoped);
        container.Register<IAuthenticationManager>(() =>
            AdvancedExtensions.IsVerifying(container)
                ? new OwinContext(new Dictionary<string, object>()).Authentication
                : HttpContext.Current.GetOwinContext().Authentication, Lifestyle.Scoped);

        container.Register<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(Lifestyle.Scoped);

        container.Register<IUnitOfWork, UnitOfWork.UnitOfWork>(Lifestyle.Scoped);
        container.RegisterCollection(typeof(IRepository<>), typeof(IRepository<>).Assembly);
        container.Register<TestService>(Lifestyle.Scoped);
    }

I get the error:

An exception of type 'System.InvalidOperationException' occurred in SimpleInjector.dll but was not handled in user code

Additional information: The configuration is invalid. Creating the instance for type TestService failed. The constructor of type TestService contains the parameter with name 'calls' and type IRepository<Call> that is not registered. Please ensure IRepository<Call> is registered, or change the constructor of TestService. There is, however, a registration for IEnumerable<IRepository<Call>>; Did you mean to depend on IEnumerable<IRepository<Call>>?

I've also, tried

container.RegisterCollection<IRepository>(new [] {typeof(IRepository)});
container.RegisterCollection(typeof(IRepository), new[] {typeof(IRepository)});

My intention is to get an instance of GenericRepository as this implents IRepository as shown in the answer in the link above.

1条回答
爷的心禁止访问
2楼-- · 2019-08-01 05:14

The exception message you get is actually pretty clear (or at least, to me):

Please ensure IRepository<Call> is registered, or change the constructor of TestService. There is, however, a registration for IEnumerable<IRepository<Call>>; Did you mean to depend on IEnumerable<IRepository<Call>>?

In other words, you made the following registration:

container.RegisterCollection(typeof(IRepository<>), typeof(IRepository<>).Assembly);

RegisterCollection means that registrations can be resolved as collection. Your TestService however depends on IRepository<Call> instead of IEnumerable<IRepository<Call>>.

Since I think it is unlikely that your application will use multiple implementations for IRepository<Call> at the same time, registration of collections is probably not what you want; there is likely a one-to-one mapping between a closed version of the generic IRepository<T> interface and an implementation.

So instead, make the registration as follows:

container.Register(typeof(IRepository<>), new[] { typeof(IRepository<>).Assembly });

This ensures the one-to-one mapping and will throw an exception in case there accidentally are more implementations for the same closed generic type.

查看更多
登录 后发表回答