Castle windsor:如何将参数传递给深度依赖项?
Castle windsor: how to pass arguments to deep dependencies?
我有以下依赖链:
IUserAppService
IUserDomainService
IUserRepository
IUserDataContext - UserDataContextImpl(string conn)
以上所有接口和实现都注册在温莎城堡容器中。当我使用一个连接字符串时,一切正常。
现在我们要支持多数据库,在UserAppServiceImpl.cs
中,我们要根据userId
得到不同的IUserRepository
(不同的IUserDatabaseContext
)如下:
// UserAppServiceImpl.cs
public UserInfo GetUserInfo(long userId)
{
var connStr = userId % 2 == 0 ? "conn1" : "conn2";
//var repo = container.Resolve<IUserRepository>(....)
}
如何将参数 connStr
传递给 UserDataContextImpl
?
您必须从依赖项解析器的开头开始,并将所有派生的依赖项解析为 "named" 分辨率。
Github代码link:https://github.com/castleproject/Windsor/blob/master/docs/inline-dependencies.md
示例:
我有一个用于 MSSQL 的 IDataContext 和一个用于 MySQL 的 IDataContext。
这个例子是在 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 完成它的工作,而无需任何开发人员了解我的容器配置。开发人员只需使用正确的服务,一切都已实现。
由于连接字符串在您的情况下是运行时数据,因此不应将其直接注入到组件的构造函数中,如 here 所述。然而,由于连接字符串是 上下文数据 ,因此将它与对象图中的所有 public 方法一起传递会很尴尬。
相反,您应该将其隐藏在允许您为当前请求检索正确值的抽象之后。例如:
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"]);
}
我有以下依赖链:
IUserAppService
IUserDomainService
IUserRepository
IUserDataContext - UserDataContextImpl(string conn)
以上所有接口和实现都注册在温莎城堡容器中。当我使用一个连接字符串时,一切正常。
现在我们要支持多数据库,在UserAppServiceImpl.cs
中,我们要根据userId
得到不同的IUserRepository
(不同的IUserDatabaseContext
)如下:
// UserAppServiceImpl.cs
public UserInfo GetUserInfo(long userId)
{
var connStr = userId % 2 == 0 ? "conn1" : "conn2";
//var repo = container.Resolve<IUserRepository>(....)
}
如何将参数 connStr
传递给 UserDataContextImpl
?
您必须从依赖项解析器的开头开始,并将所有派生的依赖项解析为 "named" 分辨率。
Github代码link:https://github.com/castleproject/Windsor/blob/master/docs/inline-dependencies.md
示例:
我有一个用于 MSSQL 的 IDataContext 和一个用于 MySQL 的 IDataContext。
这个例子是在 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 完成它的工作,而无需任何开发人员了解我的容器配置。开发人员只需使用正确的服务,一切都已实现。
由于连接字符串在您的情况下是运行时数据,因此不应将其直接注入到组件的构造函数中,如 here 所述。然而,由于连接字符串是 上下文数据 ,因此将它与对象图中的所有 public 方法一起传递会很尴尬。
相反,您应该将其隐藏在允许您为当前请求检索正确值的抽象之后。例如:
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"]);
}