4

我使用的使用工作模式爲單位的存儲庫:統一:多PerResolveLifetimeManager註冊類型的注射

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被注入到哪個存儲庫?

編輯:

使用丹尼爾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>>() 
    ) 
); 

但以下異常被拋出:

[ResolutionFailedException:分辨率的依賴失敗,輸入 =「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) 
    { } 
} 

我也註冊了實體工廠。即:

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

EntityFrameworkUnitOfWork構造:

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

    ... 
} 
+0

你可以發佈'UserRepository'的構造函數嗎? –

+0

問題更新 – davenewza

+0

剛編輯我的答案。在使用'InjectionConstructor'註冊類型時,您需要考慮Unity將使用的構造函數中的其他依賴項。這很麻煩,對重構不友好,所以我會留下一個'IUnitOfWork'作爲默認註冊(例如User和Token存儲庫),併爲其他存儲庫使用一個命名註冊和'InjectionConstructor'(在那個例如OrderRepository) –

回答

9

您可以使用named registrations這樣你就可以註冊和解析不同口味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,它允許您爲任何依賴項指定一個命名註冊。 (見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的情況下,我們需要額外的信息添加到註冊,所以團結知道IUnitOfWork依賴性應該使用指定的命名註冊而不是默認的註冊解決。

有了這些記錄,假設你曾與以下相關的類:

public FooClass(IOrderRepository orderRepository, IUserRepository userRepository, ITokenRepository tokenRepository) 
{ 
    ... 
} 
  • 兩個userRepositorytokenRepository將得到IUnitOfWork相同的實例,這將使用UserDbContext上下文。

  • orderRepository將獲得不同的IUnitOfWork實例,該實例使用OrderDbContext上下文。

編輯

當使用new InjectionConstructor你需要考慮你想要使用的構造函數的所有參數。對於您的存儲庫,您在構造函數中有IUnitOfWorkIEntityFactory<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) 
    { } 
    
  • 構造你會在這2種方法之一添加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註冊之一作爲默認註冊之一,從而避免在註冊表中使用InjectionConstructor他使用默認的UnitOfWork存儲庫。

編輯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) 
    { 
    } 

} 

統一容器註冊:

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

現在一切正常。感謝你的回答。你應該得到更多的讚揚。 – davenewza