Unity构造函数注入不按预期解析存储库

时间:2011-12-03 21:39:08

标签: dependency-injection unity-container repository-pattern repository

我正在使用Unity来解决针对多个数据库的Mike Hadlow's implementation of generic repositories(linq to sql flavor)。有效的容器配置:

container.RegisterType<IConnectionStringProvider, HistoryConnectionProvider>(new TransientLifetimeManager())
         .RegisterType<IConnectionStringProvider, MetaConnectionProvider>("meta", new TransientLifetimeManager())
         .RegisterType<IDataContextProvider, DataContextProvider>(new TransientLifetimeManager())
         .RegisterType<IDataContextProvider, DataContextProvider>("meta", new TransientLifetimeManager(), new InjectionConstructor(new ResolvedParameter<IConnectionStringProvider>("meta")))
         // this registration of Repository<> resolves the history database by default
         .RegisterType(typeof(IRepository<>), typeof(Repository<>), new TransientLifetimeManager());
         // anything not targeting this database has to be declared
         .RegisterType<IRepository<SpecificType>, Repository<SpecificType>>(new TransientLifetimeManager(), new InjectionConstructor(new ResolvedParameter<DataContextProvider>("meta")));

这似乎不必要地冗长。所以我现在正在尝试不同的方法。为每个数据库使用单独的接口:

IConnectionStringProvider historyConnectionProvider = new ConnectionProvider(connections.HistoryConnectionString);
IConnectionStringProvider metaConnectionProvider = new ConnectionProvider(connections.MetaConnectionString);

container.RegisterType<IDataContextProvider, DataContextProvider>("history", new TransientLifetimeManager(), new InjectionConstructor(historyConnectionProvider))
         .RegisterType<IDataContextProvider, DataContextProvider>("meta", new TransientLifetimeManager(), new InjectionConstructor(metaConnectionProvider))
         .RegisterType(typeof(IHistoryRepository<>), typeof(Repository<>), new TransientLifetimeManager(), new InjectionConstructor(new ResolvedParameter<IDataContextProvider>("history")))
         .RegisterType(typeof(IMetaRepository<>), typeof(Repository<>), new TransientLifetimeManager(), new InjectionConstructor(new ResolvedParameter<IDataContextProvider>("meta")));

不幸的是,这不起作用。结果是注册的最后一种类型的IDataContextProvider被注入到每种类型的存储库中。提前感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

Daniel,关于第二组代码命名单独注册的目的是什么?您已经决定为每个数据库设置单独的接口,因此似乎也不需要在其上添加名称。我可能会误解。此外,在第二个例子中,如果Respository可以实现IMeta和IHistory的接口,那么它就会产生两个问题之间的区别。

如果我给你的示例代码如何实现你想要的东西,它看起来与你所拥有的第一个例子非常相似,实际上它并不比后者更冗长。

答案 1 :(得分:0)

解决原始问题

Unity需要一个独特的类型,以及界面。我仍然不确定为什么构造函数注入没有处理这个问题。这有效:

// where IMetaRepository<T> and MetaRepository<T> both are derived place holders
container.RegisterType(typeof(IMetaRepository<>), typeof(MetaRepository<>), new TransientLifetimeManager());

不幸的是,这就形成了这样一种情况:消费类需要知道他们的数据来自何处,我对此并不满意。

更好的设计

我想保留我的dbmls生成(所以这排除了让我的模型遵循某个接口),所以我只是把它们放在不同的子文件夹中,导致设计者为每个数据库生成不同的命名空间。

然后,在我的Repository实现中,我执行了以下操作:

public Repository(IConnections connections)
{
  T type = new T();
  var ns = type.GetType().Namespace;
  if (ns == "Project.Common.DAL.History")
  {
    _dataContext = new DataContext(connections.HistoryConnectionString);
  }
  else if (ns == "Project.Common.DAL.Transaction")
  {
    _dataContext = new DataContext(connections.TransactionConnectionString);
  }
  else
  {
    _dataContext = new DataContext(connections.MetaConnectionString);
  }
}

我认为过去一步就是为Unity构建一个自定义类型解析器,以便为我检查命名空间并返回注入数据上下文(这在实现工作单元之前是必要的)。如果有人有更好的解决方案,我不打算将此作为答案。

相关问题