【问题标题】:Unity constructor injection not resolving repositories as expectedUnity构造函数注入未按预期解析存储库
【发布时间】:2011-12-17 05:44:56
【问题描述】:

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

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 被注入到每种类型的存储库中。提前感谢您的帮助。

【问题讨论】:

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


    【解决方案1】:

    Daniel,在第二组代码中,命名单独注册的目的是什么?您已经决定为每个数据库设置单独的接口,因此似乎也不需要为其命名。不过我可能是误会了。此外,在第二个示例中,如果 Respository 可以同时实现 IMeta 和 IHistory 的接口,那么它提出了一个问题,两者之间有什么区别。

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

    【讨论】:

    • 嗨,Rob,感谢您的回复。在我们得到 50 个以元数据库为目标的存储库之后,我们在目标历史中的默认行为的例外情况将是大量代码。能够声明 IHistoryRepository 并获得针对该数据库的 repo,而不是每次都抛出异常,似乎更容易。至于命名 IDataContextProviders,我希望它们的生命周期由容器处理(最终每个 Web 请求),所以觉得有必要注册它们。你是对的,没有区别。
    【解决方案2】:

    原始问题的解决方案

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-09
      • 1970-01-01
      • 2011-01-02
      • 2012-10-27
      相关资源
      最近更新 更多