
[英]Register multiple implementations of same interface in Castle Windsor
[英]Castle Windsor injecting controller with two instances of same interface
我有这样的控制器
public class MyController : Controller
{
private IEntityRepository accountsRepo;
private IEntityRepository dataRepo;
public MyController(IEntityRepository accs, IEntityRepository data)
{
accountsRepo = accs;
dataRepo = data;
}
.....
}
我以这种方式安装了容器:
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IEntityRepository>()
.ImplementedBy<AccountsRepository>()
.Named("accs")
.LifestyleTransient(),
Component.For<IEntityRepository>()
.ImplementedBy<DataRepository>()
.Named("data")
.LifestyleTransient());
}
}
我还设置了以下设施:
public class PersistenceFacility : AbstractFacility
{
protected override void Init()
{
Kernel.Register(
Component.For<DbContext>()
.ImplementedBy<AccountsContext>()
.LifestylePerWebRequest(),
Component.For<DbContext>()
.ImplementedBy<DataContext>()
.LifestylePerWebRequest());
}
}
}
...并安装:
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<PersistenceFacility>();
}
}
因此,当我使用控制器时,两个参数都将与AccountsRepository实例一起注入(该实例首先被注册)。 当然,我想分别将“数据”作为DataRepository。 请给我解释处理这种注射的正确方法。
编辑
正如@roman所建议的,我已经实现了通用存储库:
public interface IRepository : IDisposable
{
void SaveChanges();
void ExecuteProcedure(String procedureCommand, params SqlParameter[] sqlParams);
}
public interface IEntityRepository<T> : IRepository
{
T Context { get; set; }
DbSet<TEntity> Set<TEntity>() where TEntity : class;
}
public class AccountsRepository : IEntityRepository<AccountsContext>
{
public AccountsContext Context { get; set; }
public AccountsRepository(AccountsContext c)
{
Context = c;
}
public DbSet<TEntity> Set<TEntity>() where TEntity : class
{
return Context.Set<TEntity>();
}
public virtual void ExecuteProcedure(String procedureCommand, params SqlParameter[] sqlParams)
{
Context.Database.ExecuteSqlCommand(procedureCommand, sqlParams);
}
public virtual void SaveChanges()
{
Context.SaveChanges();
}
public void Dispose()
{
if (Context != null)
Context.Dispose();
}
}
DataRepository看起来是一样的,在某种程度上,我将决定只拥有一个具体的类EntityRepository,但它与我收到的异常无关。 因此,在外观界面更改后,我的控制者变为:
public class HomeController : Controller
{
private IEntityRepository<AccountsContext> accountsRepo;
private IEntityRepository<DataContext> dataRepo;
public HomeController(IEntityRepository<AccountsContext> accs, IEntityRepository<DataContext> data)
{
accountsRepo = accs;
dataRepo = data;
}
....
}
我也更改了安装程序代码:
container.Register(
Component.For<IEntityRepository<AccountsContext>>()
.ImplementedBy<AccountsRepository>()
.LifestyleTransient(),
Component.For<IEntityRepository<DataContext>>()
.ImplementedBy<DataRepository>()
.LifestyleTransient());
现在在控制器解决过程中
return (IController) kernel.Resolve(controllerType);
我赶上
无法创建组件“ MyMVCProj.DAL.AccountsRepository”,因为它具有要满足的依赖关系。
'MyMVCProj.DAL.AccountsRepository' is waiting for the following dependencies:
- Service 'MyMVCProj.DAL.AccountsContext' which was not registered.
Castle.MicroKernel.Handlers.HandlerException: Can't create component 'MyMVCProj.DAL.AccountsRepository' as it has dependencies to be satisfied.
'MyMVCProj.DAL.AccountsRepository' is waiting for the following dependencies:
- Service 'MyMVCProj.DAL.AccountsContext' which was not registered.
但是我已经在设施逻辑中安装了AccountsContext。
编辑++根据@Roman的建议,我以这种方式调整了我的设施:
public class PersistenceFacility : AbstractFacility
{
protected override void Init()
{
Kernel.Register(
Component.For<DbContext>()
.ImplementedBy<AccountsContext>()
.Named("accctx")
.LifestylePerWebRequest(),
Component.For<DbContext>()
.ImplementedBy<DataContext>()
.Named("datactx")
.LifestylePerWebRequest());
}
}
以及仓库安装程序:
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IEntityRepository<AccountsContext>>()
.ImplementedBy<AccountsRepository>()
.Named("accs")
.LifestyleTransient()
.DependsOn(Dependency.OnComponent(typeof (DbContext), "accctx")),
Component.For<IEntityRepository<DataContext>>()
.ImplementedBy<DataRepository>()
.Named("data")
.LifestyleTransient()
.DependsOn(Dependency.OnComponent(typeof (DbContext), "datactx")));
}
}
这是我现在得到的例外:
Can't create component 'accs' as it has dependencies to be satisfied.
'accs' is waiting for the following dependencies:
- Service 'MyMVCProj.DAL.AccountsContext' which was not registered.
但是,为了解决这种残酷的行为,我以有效的解决方案结束了代码,只是安装了DBContext的具体实现:
public class PersistenceFacility : AbstractFacility
{
protected override void Init()
{
Kernel.Register(
Component.For<AccountsContext>().LifestylePerWebRequest(),
Component.For<DataContext>().LifestylePerWebRequest());
}
}
现在内核的组件是:
AccountsContext PerWebRequest
AccountsRepository / IEntityRepository<AccountsContext> Transient
DataContext PerWebRequest
DataRepository / IEntityRepository<DataContext> Transient
在他们之前:
AccountsContext / DbContext PerWebRequest
AccountsRepository / IEntityRepository<AccountsContext> Transient
DataContext / DbContext PerWebRequest
DataRepository / IEntityRepository<DataContext> Transient
因此,新问题是:
我是否习惯了所有工作? 为什么会出现这种行为-已经有AccountContext很少提及它的依赖关系。
您期望有相同接口的两个实例,但您需要对它们采取不同的行为(通过将它们注入两个不同的参数),这一事实(在我看来)意味着它们不应该是同一接口,因为它们具有不同的作用,或责任。 如果IEntityRepository是一个通用类,那么对我来说更有意义,那么您将在MyController中要求两种不同的通用接口类型:
public class MyController(IEntityRepository<Account> acc, IEntityRepository<Data> data)
不过,如果您仍然想做这种事情,我建议您使用CollectionResolver,它将允许MyController类获取IEnumerable。 这样,您将获得两个实例,但是将取决于您的需求来选择合适的实例,我会再次强调,我认为这是错误的方法。
要使用CollectionResolver,您需要像这样在Windsor容器中注册它:
var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
然后,MyController将如下所示:
public class MyController(IEnumerable<IEntityRepository> repositories)
{
accountsRepo = repositories.Where(...);
dataRepo = repositories.Where(...);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.