Unity:多个PerResolveLifetimeManager已注册类型的注入

4

我正在使用采用工作单元模式的代码库:

public BaseRepository(IUnitOfWork unitOfWork, IEntityFactory factory) { ... }

以前,我只需要将一个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>();

现在我需要介绍另一个仓库,但是这个仓库需要使用不同实例的 IUnitOfWork

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

container.RegisterType<IOrderRepository, OrderRepository>();

我怎样使用Unity来明确指定哪个IUnitOfWork被注入到哪个repository中呢?
编辑:
使用Daniel J.G的答案,我有以下代码:
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>>()
    )
);

但是出现了以下异常:

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

UserRepository 具体实现:
public class UserRepository : EntityFrameworkRepository<User, UserTbl>, IUserRepository
{
    public UserRepository(IUnitOfWork unitOfWork, IEntityFactory<User, UserTbl> factory)
        : base(unitOfWork, factory)
    { }
}

我还在注册实体工厂。 例如:

container.RegisterType<IEntityFactory<User, int, UserTbl>, UserFactory>();

EntityFrameworkUnitOfWork构造函数:

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

    ...
}

你能发布UserRepository的构造函数吗? - Daniel J.G.
刚刚编辑了我的答案。在使用InjectionConstructor注册类型时,您需要考虑构造函数中Unity将使用的其他依赖项。这很麻烦,而且不太容易重构,因此我会将一个IUnitOfWork的注册作为默认注册(例如User和Token存储库的注册),并为其他存储库(在该示例中为OrderRepository)使用命名注册和InjectionConstructor - Daniel J.G.
我现在又遇到了另一个异常:_类型IUnitOfWork没有可访问的构造函数_。问题已更新。再次感谢。 - Dave New
请再次检查您的命名注册,以防万一。参见此问题 - Daniel J.G.
1
我添加了一些示例代码,我可以解决所有依赖关系。从一个依赖项开始添加注册/解析代码,看看是否可以通过这种方式缩小问题范围。您是否有其他可能会干扰的注册代码? - Daniel J.G.
最后一个错误解决了吗? - Daniel J.G.
1个回答

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()));

使用上面的代码,当您解析IUnitOfWork实例时,如果不指定任何名称,例如container.Resolve<IUnitOfWork>,则会得到使用UserDbContext的实例。要获取任何命名实例,您需要执行类似于container.Resolve<IUnitOfWork>("OrderUow")的操作,这将为您提供使用OrderDbContext的实例。(当您想要使用命名注册时,始终必须通过传递名称来解决类型)
唯一剩下的事情是正确连接注入参数以获取您的存储库所需的IUnitOfWork实例。您可以配置一个ResolvedParameter来进行配置,它允许您为任何依赖项指定命名注册。(请参见此SO问题)
这样,连接您的存储库的代码如下所示:
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>>()));

请注意,仅在订单存储库的情况下,我们需要在注册中添加额外信息,这样Unity才知道应该使用指定的命名注册而不是默认注册来解析IUnitOfWork依赖项。有了这些注册,假设您有一个具有以下依赖关系的类:
public FooClass(IOrderRepository orderRepository, IUserRepository userRepository, ITokenRepository tokenRepository)
{
    ...
}
  • 无论是userRepository还是tokenRepository都将获取相同的IUnitOfWork实例,该实例将使用UserDbContext上下文。

  • orderRepository将获取一个不同的IUnitOfWork实例,该实例将使用OrderDbContext上下文。

编辑

在使用new InjectionConstructor时,您需要考虑要使用的构造函数的所有参数。在您的仓库中,构造函数中有IUnitOfWorkIEntityFactory<T1, T2>作为依赖项。我已经更新了IOrderRepository的注册,假设它具有IEntityFactory<Order,OrderTbl>类型的依赖项(对于UserRepository而言,这将是IEntityFactory<User, UserTbl>类型)。

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

  • In other words, if you have a constructor like

    public UserRepository(IUnitOfWork unitOfWork, IEntityFactory<User, UserTbl> factory)
        : base(unitOfWork, factory)
    { }
    
  • You would add an InjectionConstructor in one of these 2 ways:

    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>>)));
    

这有点繁琐,所以我建议将其中一个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)
    {
    }

}

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>();

虚拟控制器需要这些存储库:

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();
    }
}

一切都正常工作了。感谢您的回答。您应该得到更多的赞。 - Dave New

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接