c# - 统一: Injection of multiple PerResolveLifetimeManager registered types

标签 c# dependency-injection unity-container repository-pattern ioc-container

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

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

以前我只需要将一个 IUnitOfWork 实例注入(inject)到存储库中(使用 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 注入(inject)哪个存储库?

编辑:

使用 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: Resolution of the dependency failed, type = "WebTest.Controllers.TestController", name = "(none)". Exception occurred while: while resolving. Exception is: InvalidOperationException - The type IUnitOfWork does not have an accessible constructor.

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

    ...
}

最佳答案

您可以使用 named registrations所以你可以注册并解析 IUnitOfWork 的不同flavours .

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 的实例。 (当你想使用命名注册时,你总是被迫解析传递名称的类型)

唯一剩下的就是为您的存储库正确连接注入(inject)参数,以便它们获得正确的 IUnitOfWork实例。您可以通过配置 ResolvedParameter 来做到这一点,它允许您为任何依赖项指定命名注册。 (参见 this SO question)

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

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

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

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

public FooClass(IOrderRepository orderRepository, IUserRepository userRepository, ITokenRepository tokenRepository)
{
    ...
}
  • 两者都是 userRepositorytokenRepository将获得 IUnitOfWork 的相同实例,这将使用 UserDbContext上下文。

  • orderRepository会得到一个不同的 IUnitOfWork例如,它使用 OrderDbContext上下文。

编辑

使用 new InjectionConstructor 时您需要考虑要使用的构造函数的所有参数。对于您的存储库,您有 IUnitOfWorkIEntityFactory<T1, T2>作为构造函数中的依赖项。我更新了IOrderRepository的注册上面有一个依赖项,我猜是 IEntityFactory<Order,OrderTbl> 类型的(对于类型为 IEntityFactory<User, UserTbl> 的 UserRepository)。

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

  • 换句话说,如果你有一个像

    这样的构造函数
    public UserRepository(IUnitOfWork unitOfWork, IEntityFactory<User, UserTbl> factory)
        : base(unitOfWork, factory)
    { }
    
  • 您可以通过以下两种方式之一添加 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>>)));
    

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

编辑 2 - 示例代码

虚拟接口(interface)和实现:

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

需要存储库的虚拟 Controller :

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

关于c# - 统一: Injection of multiple PerResolveLifetimeManager registered types,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21455981/

相关文章:

c# - 如何将 Unity 与内部类一起使用?

c# - 批处理文件在服务器上不起作用但在本地工作

c# - 从桌面应用程序发送短信

c# - 如何从 Windows 窗体中的图表中删除网格线?

dependency-injection - 温莎城堡 : OnCreate for BaseOnDescriptor

c# - 你如何处理 IoC 和 DI 的 'deep' 依赖项?

c# - ASP.NET 中的 View 状态和控件

android - Dagger 2 Presenter 注入(inject)返回空值

java - Spring接口(interface)注入(inject)示例

c# - Resharper 和自定义实时模板不工作