Unity:注入多个PerResolveLifetimeManager注册类型

Dav*_*New 4 c# dependency-injection ioc-container unity-container repository-pattern

我正在使用使用工作单元模式的存储库:

public BaseRepository(IUnitOfWork unitOfWork, IEntityFactory factory) { ... }
Run Code Online (Sandbox Code Playgroud)

以前我只需要将一个IUnitOfWork实例注入存储库(使用Unity),如下所示:

// Unit of work for the UserDbContext
container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>(new PerResolveLifetimeManager(), new InjectionConstructor(new UserDbContext()));

container.RegisterType<IUserRepository, UserRepository>();
container.RegisterType<ITokenRepository, TokenRepository>();
Run Code Online (Sandbox Code Playgroud)

现在我需要引入另一个存储库,但是这个存储库需要使用以下的不同实例IUnitOfWork:

// Unit of work for the OrderDbContext
container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>(new PerResolveLifetimeManager(), new InjectionConstructor(new OrderDbContext()));

container.RegisterType<IOrderRepository, OrderRepository>();
Run Code Online (Sandbox Code Playgroud)

如何使用Unity明确指定将哪个IUnitOfWork注入哪个存储库?

编辑:

使用Daniel JG的答案,我有以下代码:

container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>(new PerResolveLifetimeManager(), new InjectionConstructor(new UserDbContext()));
container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>("OrderDbContext", new PerResolveLifetimeManager(), new InjectionConstructor(new OrderDbContext()));

container.RegisterType<IUserRepository, UserRepository>();
container.RegisterType<ITokenRepository, TokenRepository>();

container.RegisterType<IOrderRepository, OrderRepository>(
    new InjectionConstructor(
        new ResolvedParameter<IUnitOfWork>("OrderDbContext"),
        new ResolvedParameter<IEntityFactory<Order, int, OrderTbl>>()
    )
);
Run Code Online (Sandbox Code Playgroud)

但是抛出了以下异常:

[ResolutionFailedException:依赖项的解析失败,type ="WebTest.Controllers.TestController",name ="(none)".在解决时发生异常:异常是: InvalidOperationException - IUnitOfWork类型没有可访问的构造函数.

UserRepository具体实现:

public class UserRepository : EntityFrameworkRepository<User, UserTbl>, IUserRepository
{
    public UserRepository(IUnitOfWork unitOfWork, IEntityFactory<User, UserTbl> factory)
        : base(unitOfWork, factory)
    { }
}
Run Code Online (Sandbox Code Playgroud)

我也在注册实体工厂.即:

container.RegisterType<IEntityFactory<User, int, UserTbl>, UserFactory>();
Run Code Online (Sandbox Code Playgroud)

EntityFrameworkUnitOfWork构造函数:

public class EntityFrameworkUnitOfWork : IUnitOfWork
{
    public EntityFrameworkUnitOfWork(DbContext context)
    {
        Context = context;
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*.G. 9

您可以使用命名注册,因此您可以注册和解析不同口味IUnitOfWork.

Unity提供了一个未命名的注册(这是默认注册)以及您需要的多个命名注册.因此,您可以将其中一个IUnitOfWork没有名称的注册作为默认注册,并添加另一个命名注册.例如:

container.RegisterType<IUnitOfWork, UnitOfWork>(new PerResolveLifetimeManager(), 
                                                new InjectionConstructor(new UserDbContext()));

container.RegisterType<IUnitOfWork, UnitOfWork>("OrderUow", 
                                                new PerResolveLifetimeManager(), 
                                                new InjectionConstructor(new OrderDbContext()));
Run Code Online (Sandbox Code Playgroud)

使用上面的代码,当您解析实例IUnitOfWork而不指定任何名称时,container.Resolve<IUnitOfWork>您将获得使用UserDbContext的实例.要获取任何命名实例,您需要执行类似操作container.Resolve<IUnitOfWork>("OrderUow"),它将为您提供使用OrderDbContext的实例.(如果要使用命名注册,则始终强制解析传递名称的类型)

剩下的唯一事情是正确连接存储库的注入参数,以便它们获得正确的IUnitOfWork实例.您可以这样做,配置a ResolvedParameter,它允许您为任何依赖项指定命名注册.(见这个问题)

这样,用于连接存储库的代码如下:

container.RegisterType<IUserRepository, UserRepository>();
container.RegisterType<ITokenRepository, TokenRepository>();
container.RegisterType<IOrderRepository, OrderRepository>(new InjectionConstructor(
                                       new ResolvedParameter<IUnitOfWork>("OrderUow"),
                                       //additional dependencies in the OrderRepository constructor, resolved using default Unity registrations
                                       new ResolvedParameter<IEntityFactory<Order,OrderTbl>>()));
Run Code Online (Sandbox Code Playgroud)

请注意,只有在OrderRepository的情况下,我们需要向注册添加额外信息,因此Unity知道IUnitOfWork应该使用指定的命名注册而不是默认注册来解析依赖项.

有了这些注册,假设您有一个具有以下依赖项的类:

public FooClass(IOrderRepository orderRepository, IUserRepository userRepository, ITokenRepository tokenRepository)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)
  • 双方userRepositorytokenRepository会得到相同的实例IUnitOfWork,其中将要使用的UserDbContext上下文.

  • orderRepository将获得一个IUnitOfWork使用OrderDbContext上下文的不同实例.

编辑

使用时,new InjectionConstructor您需要考虑要使用的构造函数的所有参数.在您的库,你需要的情况下IUnitOfWork,并IEntityFactory<T1, T2>在构造函数依赖.我已经更新了IOrderRepository上面的注册与我猜测类型的依赖关系IEntityFactory<Order,OrderTbl>(在UserRepository的情况下将是类型IEntityFactory<User, UserTbl>).

要在构造函数中添加额外的依赖项,请添加更多ResolvedParameter<T>或仅添加typeOf(T).请注意,InjectionConstructor需要的参数顺序与您要注册的类型的构造函数中的参数顺序相匹配.

  • 换句话说,如果你有一个像这样的构造函数

    public UserRepository(IUnitOfWork unitOfWork, IEntityFactory<User, UserTbl> factory)
        : base(unitOfWork, factory)
    { }
    
    Run Code Online (Sandbox Code Playgroud)
  • 您可以使用以下两种方法之一添加InjectionConstructor:

    container.RegisterType<IUserRepository, UserRepository>(new InjectionConstructor(
                     //Let's assume the Uow was registered as a named registration                   
                     new ResolvedParameter<IUnitOfWork>("UserUow"),
                     //provide information about additional parameters in the constructor
                     new ResolvedParameter<IEntityFactory<User,UserTbl>>()));
    
    container.RegisterType<IUserRepository, UserRepository>(new InjectionConstructor(
                     //Let's assume the Uow was registered as a named registration                   
                     new ResolvedParameter<IUnitOfWork>("UserUow"),
                     //provide information about additional parameters in the constructor
                     typeof(<IEntityFactory<User,UserTbl>>)));
    
    Run Code Online (Sandbox Code Playgroud)

这有点麻烦,所以我将其中一个UnitOfWork注册作为默认注册,从而避免在使用默认UnitOfWork的存储库上使用InjectionConstructor.

编辑2 - 示例代码

虚拟接口和实现:

public class DbContext
{
    public string Name { get; set; }
}

public interface IUnitOfWork
{
    DbContext DbContext { get; }
}    

public class UnitOfWork : IUnitOfWork
{
    private readonly DbContext _dbContext;
    public UnitOfWork(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public DbContext DbContext { get { return _dbContext; } }
}

public interface IOrderRepository
{
    IUnitOfWork UnitOfWork { get;}
}

public class BaseRepository
{
    private readonly IUnitOfWork _uow;
    public BaseRepository(IUnitOfWork uow)
    {
        _uow = uow;
    }

    public IUnitOfWork UnitOfWork { get { return _uow; } }
}

public class OrderRepository : BaseRepository, IOrderRepository
{
    private IFooAdditionalDependency _foo;
    public OrderRepository(IUnitOfWork uow, IFooAdditionalDependency foo)
        : base(uow)
    {
        _foo = foo;
    }
}

public interface IFooAdditionalDependency { }
public class FooAdditionalDependency : IFooAdditionalDependency
{
}

public interface IUserRepository
{
    IUnitOfWork UnitOfWork { get; }
}

public class UserRepository : BaseRepository, IUserRepository
{
    public UserRepository(IUnitOfWork uow)
        : base(uow)
    {
    }
}



public interface ITokenRepository
{
    IUnitOfWork UnitOfWork { get; }
}

public class TokenRepository : BaseRepository, ITokenRepository
{
    public TokenRepository(IUnitOfWork uow)
        : base(uow)
    {
    }

}
Run Code Online (Sandbox Code Playgroud)

Unity容器注册:

container.RegisterType<IUnitOfWork, UnitOfWork>(new PerResolveLifetimeManager(), 
                                    new InjectionConstructor(new DbContext{Name = "UserDB"}));
container.RegisterType<IUnitOfWork, UnitOfWork>("OrderDbContext", 
                                    new PerResolveLifetimeManager(),
                                    new InjectionConstructor(new DbContext { Name = "OrderDB" }));

container.RegisterType<IUserRepository, UserRepository>();
container.RegisterType<ITokenRepository, TokenRepository>();
container.RegisterType<IOrderRepository, OrderRepository>(new InjectionConstructor(
                                    new ResolvedParameter<IUnitOfWork>("OrderDbContext"),                                                                
                                    typeof(IFooAdditionalDependency)));

container.RegisterType<IFooAdditionalDependency, FooAdditionalDependency>();
Run Code Online (Sandbox Code Playgroud)

需要存储库的虚拟控制器:

public class HomeController : Controller
{
    public HomeController(IOrderRepository orderRepository, IUserRepository userRepository, ITokenRepository tokenRepository)
    {
        Debug.WriteLine("Order repository context: {0}, User repository context:{1}", orderRepository.UnitOfWork.DbContext.Name, userRepository.UnitOfWork.DbContext.Name);
        Debug.WriteLine("Order repository context: {0}, User repository context:{1}", orderRepository.UnitOfWork.DbContext.GetType().Name, userRepository.UnitOfWork.DbContext.GetType().Name);
        Debug.Assert(orderRepository.UnitOfWork != userRepository.UnitOfWork);
        Debug.Assert(userRepository.UnitOfWork == tokenRepository.UnitOfWork);
    }

    public ActionResult Index()
    {
        return View();
    }
}
Run Code Online (Sandbox Code Playgroud)