Castle windsor:如何将参数传递给深度依赖?

时间:2017-03-20 01:55:27

标签: castle-windsor

我有以下依赖链:

IUserAppService
IUserDomainService 
IUserRepository
IUserDataContext - UserDataContextImpl(string conn) 

上面的所有接口和实现都在Windsor Castle容器中注册。当我使用一个连接字符串时,一切正常。

现在我们要支持多个数据库,在UserAppServiceImpl.cs中,我们希望根据IUserRepository获得不同的IUserDatabaseContext(不同userId),如下所示:

// UserAppServiceImpl.cs
public UserInfo GetUserInfo(long userId)
{
   var connStr = userId % 2 == 0 ? "conn1" : "conn2";
   //var repo = container.Resolve<IUserRepository>(....)
}

如何将参数connStr传递给UserDataContextImpl

2 个答案:

答案 0 :(得分:2)

由于连接字符串是您的情况下的运行时数据,因此不应将其直接注入组件的构造函数中,如here所述。但是,由于连接字符串是上下文数据,因此将它传递给对象图中的所有公共方法会很尴尬。

相反,您应该将其隐藏在抽象之后,该抽象允许您检索当前请求的正确值。例如:

public interface ISqlConnectionFactory
{
    SqlConnection Open();
}

ISqlConnectionFactory本身的实现可能依赖于允许检索当前用户ID的依赖项:

public interface IUserContext
{
    int UserId { get; }
}

这样的连接工厂可能因此看起来像这样:

public class SqlConnectionFactory : ISqlConnectionFactory
{
    private readonly IUserContext userContext;
    private readonly string con1;
    private readonly string con2;

    public SqlConnectionFactory(IUserContext userContext,
        string con1, string con2) {
        ...
    }

    public SqlConnection Open() {
        var connStr = userContext.UserId % 2 == 0 ? "conn1" : "conn2";            
        var con = new SqlConnection(connStr);
        con.Open();
        return con;
    }
}

这为我们留下了IUserContext实现。这种实现将取决于我们正在构建的应用程序类型。对于ASP.NET,它可能如下所示:

public class AspNetUserContext : IUserContext
{
    public string UserId => int.Parse(HttpContext.Current.Session["UserId"]); 
}

答案 1 :(得分:0)

您必须从依赖项解析程序的开头开始,并将所有派生的依赖项解析为“命名”解析。

Github代码链接:https://github.com/castleproject/Windsor/blob/master/docs/inline-dependencies.md

示例:

我有用于MSSQL的IDataContext和用于MySQL的另一个。

这个例子在Unity中,但我相信Windsor可以做到这一点。

        container.RegisterType(Of IDataContextAsync, dbEntities)("db", New InjectionConstructor())
        container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)("UnitOfWork", New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db")))

        'Exceptions example
        container.RegisterType(Of IRepositoryAsync(Of Exception), Repository(Of Exception))("iExceptionRepository",
                                                                                                     New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db"),
                                                                                                                              New ResolvedParameter(Of IUnitOfWorkAsync)("UnitOfWork")))

sql容器

container.RegisterType(Of IDataContextAsync, DataMart)(New HierarchicalLifetimeManager)
        container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)(New HierarchicalLifetimeManager)

        'brands
        container.RegisterType(Of IRepositoryAsync(Of Brand), Repository(Of Brand))

控制器代码: 控制器级别无需更改。

结果: 我现在可以让我的MSSQL上下文完成它的工作,MySQL可以完成它的工作,而无需任何开发人员了解我的容器配置。开发人员只需使用正确的服务即可实现所有功能。