我有以下组件组成:
public interface IJob {
ILogger Logger { get; set; }
}
public class JobC : IJob
{
public ILogger Logger { get; set; }
private ServiceA serviceA;
private ServiceB serviceB;
public JobC(ServiceA serviceA, ServiceB serviceB)
{
this.serviceA = serviceA;
this.serviceB = serviceB;
}
}
public class ServiceB
{
public ILogger Logger { get; set; }
}
public class ServiceA
{
public ILogger Logger { get; set; }
}
正如您所看到的,周围都有Logger属性。事实是,我需要在解析过程中传递该属性值(不同的工作需要不同的配置记录器)。 因此,如果只有顶级组件需要这个,那就像
一样简单var childLogger = Logger.CreateChildLogger(jobGroupName);
var job = windsorContainer.Resolve(jobType);
job.Logger = childLogger;
但是我需要将childLogger传递给树,并且该树非常复杂,我不希望手动将logger实例传递给每个组件,这需要它,想知道Windsor是否可以帮助我吗?
更新:可能这有助于更好地理解问题: 在wiki中注意到:
内联依赖项不会传播 无论您传递给Resolve方法的参数是什么,都只能用于根组件
你试图解决它的拦截器。所有组件进一步下降(root的 依赖项及其依赖项等)将无法访问它们。
为什么会这样,是否有解决方法?
更新2: 如果我能添加真实情况,可能会有所帮助。
因此,我们有应用程序,它从/向各种销售渠道发送/接收数据。每个销售渠道都有相应的工作集合,例如发送更新的产品信息,接收订单等(每个工作可能包含更小的工作)。所以合乎逻辑的是,我们需要将每个通道的日志信息与其他通道分开,但是单通道的作业日志应该转到单个监听器,我们可以看到正在发生的事情的顺序(如果每个作业和子作业都有自己的日志监听器) ,我们需要按时间合并日志以了解发生了什么。在编译时不知道某些通道及其作业集(假设有通道A,我们可以通过简单地将该国家添加到DB来启动特定国家/地区的单独通道,具体取决于我们可以切换同步方法的负载等)。
这意味着我们可能拥有UpdateProductsForChannelAJob,它将用于两个不同的渠道(ChannelA US和ChannelA UK),因此它的记录器将取决于它所依赖的渠道。
所以我们现在正在做的是,我们为每个通道创建子记录器,并在解析Job实例作为参数时传递它。这有用,但有一件烦人的事情 - 我们必须在job中手动将logger实例传递给每个依赖项(和依赖项依赖项),这可能是记录了一些东西。
更新3:
我在Windsor文档功能中找到了这听起来像我需要的东西:
有时您需要提供依赖项,在组件创建时才会知道该依赖项。例如,假设您需要为您的服务创建时间戳。您知道如何在注册时获取它,但您不知道它的具体值是什么(实际上每次创建新实例时它都会有所不同)。在这种情况下,您使用DynamicParameters方法。
你在DynamicParameters委托中得到两个参数,其中一个是字典和
现在,您可以使用依赖项来填充该字典,该依赖项将进一步传递到解析管道
鉴于此,我认为这样可行:
public interface IService
{
}
public class ServiceWithLogger : IService
{
public ILogger Logger { get; set; }
}
public class ServiceComposition
{
public ILogger Logger { get; set; }
public IService Service { get; set; }
public ServiceComposition(IService service)
{
Service = service;
}
}
public class NameService
{
public NameService(string name)
{
Name = name;
}
public string Name { get; set; }
}
public class NameServiceConsumer
{
public NameService NameService { get; set; }
}
public class NameServiceConsumerComposition
{
public NameService NameService { get; set; }
public NameServiceConsumer NameServiceConsumer { get; set; }
}
[TestFixture]
public class Tests
{
[Test]
public void GivenDynamicParamtersConfigurationContainerShouldPassLoggerDownTheTree()
{
var container = new WindsorContainer();
container.AddFacility<LoggingFacility>();
container.Register(
Component.For<IService>().ImplementedBy<ServiceWithLogger>().LifestyleTransient(),
Component.For<ServiceComposition>().DynamicParameters((k, d) =>
{
d["Logger"] = k.Resolve<ILogger>().CreateChildLogger(d["name"].ToString());
}).LifestyleTransient()
);
var service = container.Resolve<ServiceComposition>(new { name = "my child" });
var childLogger = ((ServiceWithLogger) service.Service).Logger;
Assert.IsTrue(((ConsoleLogger)childLogger).Name.Contains("my child"));
}
[Test]
public void GivenDynamicParamtersConfigurationContainerShouldPassNameDownTheTree()
{
var container = new WindsorContainer();
container.AddFacility<LoggingFacility>();
container.Register(
Component.For<NameService>().LifestyleTransient().DependsOn(new {name = "default"}),
Component.For<NameServiceConsumer>().LifestyleTransient(),
Component.For<NameServiceConsumerComposition>().DynamicParameters((k, d) =>
{
d["nameService"] = k.Resolve<NameService>(d["nameParam"]);
}).LifestyleTransient()
);
var service = container.Resolve<NameServiceConsumerComposition>(new { nameParam = "my child" });
Console.WriteLine(service.NameServiceConsumer.NameService.Name);
Assert.IsTrue(service.NameServiceConsumer.NameService.Name.Contains("my child"));
}
}
但事实并非如此。
答案 0 :(得分:2)
解析后请勿手动传递记录器。让温莎为你做。使用logging facility。
答案 1 :(得分:1)
我认为我终于明白为什么这个相对容易实现,但是在Windsor中没有实现(我认为任何其他容器)。 假设我们有以下配置:
public class TransientA
{
public SingletonC SingletonC { get; set; }
public ILogger Logger { get; set; }
}
public class TransientB
{
public SingletonC SingletonC { get; set; }
public ILogger Logger { get; set; }
}
public class SingletonC
{
public ILogger Logger { get; set; }
}
类名反映了他们的生活方式,所以如果你要在Resolve for TransientA上进行递归属性注入,你也会改变TransientB.SingletonC.Logger属性!
你可以在传播时跳过单例属性注入,但是a)会增加混乱b)无论如何都不会解决初始问题(一些日志记录将转到singlenton的记录器)。
因此,在使用递归属性注入的情况下,您需要添加限制,该组件不应该在其依赖关系层次结构中具有单独依赖关系(PerWebRequest / PerThread),这是非常有限的。