以下代码仅供演示之用。
假设我有2个组件(businessService和dataService)和一个UI类。
UI类需要业务服务,businessService需要dataService,而dataService需要依赖connectionString。
形成我需要解析业务服务的UI类,所以我写下面的代码:
var service = container.Resolve<BusinessService>(new { dependancy = "con string 123" }));
注意,dependance是connectionString构造函数参数。
但是上面的代码没有用,说dataService期望依赖性不满意。
无法创建组件'dataService' 因为它有依赖性 满意。 dataService正在等待 以下依赖项:
键(具有特定键的组件) - 未登记的依赖性。
作为一种解决方法,我这样做:
var service = container.Resolve<BusinessService>(new { dataService = container.Resolve<IDataService>(new { dependancy = "123" }) });
但是从设计,编码风格和许多角度来看,这不是一个很好的方法。
所以,如果你能告诉它为什么不能以简单的方式工作,或者你有一个更好的解决方法,请分享。
答案 0 :(得分:6)
您看到的行为是设计性的。
有两种方法可以解决问题,具体取决于您要传递的值的动态程度。
The documentation做得非常好,详细说明,所以我不会在此重申。
<强>更新强>
为了清晰起见 - Windsor不会在分辨率管道中传递内联参数。原因很简单 - 这样做会破坏抽象。调用代码必须隐含地知道您的BusinessService
依赖于DataService
,这取决于连接字符串。
如果你必须这样做,那就明白了。这就是你正在做的事情 - 明确解决DataService
依赖于连接字符串的问题,并明确解决BusinessService
传递DataService
作为依赖关系。
为了使事情真正明确(并且更好用),我建议使用Typed Factory而不是直接调用容器
public interface IFactory
{
IDataService ResolveDataService(string connectionString);
IBussinessService ResolveBussinessService(IDataService dataService);
// possibly release method for IBussinessService as well
}
答案 1 :(得分:2)
在创建需要上下文对象的瞬态组件时,我需要这样做。我使用的解决方案是覆盖DefaultDependencyResolver
类,以便它确实在分辨率管道中传递内联参数。
public class ArgumentPassingDependencyResolver : DefaultDependencyResolver
{
protected override CreationContext RebuildContextForParameter(
CreationContext current, Type parameterType)
{
if (parameterType.ContainsGenericParameters)
{
// this behaviour copied from base class
return current;
}
// the difference in the following line is that "true" is passed
// instead of "false" as the third parameter
return new CreationContext(parameterType, current, true);
}
}
创建容器时需要传入此类的实例(其他类也需要传入,因为没有方便的构造函数只接受依赖项解析器):
var container = new WindsorContainer(
new DefaultKernel(
new ArgumentPassingDependencyResolver(),
new NotSupportedProxyFactory()),
new DefaultComponentInstaller());
答案 2 :(得分:0)
是的,您要求的是可能的,但您应该通过Typed Factory Facility使用抽象工厂,而不是直接通过容器请求您的服务。
对于类型化工厂,您需要做的就是定义工厂接口,Windsor将为您完成实施。
public interface IBusinessServiceFactory {
IBusinessService CreateBusinessService(string connString);
}
public interface IDataServiceFactory {
IDataService CreateDataService(string connString);
}
添加工具并注册工厂界面,如下所示:
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IDataServiceFactory>().AsFactory());
container.Register(Component.For<IBusinessServiceFactory>().AsFactory());
您现在可以通过在BusinessService
注册中定义Dynamic Parameter来手动定义运行时参数如何通过对象图传递。
container.Register(Component.For<IBusinessService, BusinessService>()
.LifestyleTransient()
.DynamicParameters((k, d) => {
d["dataService"] = k.Resolve<IDataServiceFactory>.CreateDataService((string)d["connString"]);
}));
请记住,字典键必须与CreateBusinessService
方法和BusinessService
构造函数中的参数名称匹配。
如果您打算在每次调用工厂方法时创建新实例,也应该将其设为LifestyleTransient。 (默认为单身)