【发布时间】:2011-12-14 07:41:13
【问题描述】:
我有以下组件组成:
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 向下传递,而且该树非常复杂,我不希望手动将记录器实例传递给每个需要它的组件,想知道 Windsor 是否可以帮助我?
更新:这可能有助于更好地理解问题: 在wiki 有通知:
内联依赖不会被传播 无论您传递给 Resolve 方法的任何参数都将仅对根组件可用
您正在尝试解决,以及它的拦截器。所有组件进一步向下(根的 依赖项,以及它们的依赖项等)将无法访问它们。
为什么会这样,有什么解决方法吗?
更新 2: 如果我添加真实情况,可能会有所帮助。
因此,我们有应用程序,它从各种销售渠道发送/接收数据。每个销售渠道都有相应的作业集合,例如发送更新的产品信息、接收订单等(每个作业可能包含较小的作业)。所以这是合乎逻辑的,我们需要将每个通道的日志信息与其他通道分开,但是单个通道的作业日志应该转到单个侦听器,我们可以看到正在发生的事情的顺序(如果每个作业和子作业都有自己的日志记录侦听器,我们需要按时间合并日志以了解发生了什么)。一些频道及其工作集在编译时是未知的(假设有频道 A,我们可以通过简单地将特定国家添加到 DB 中来为特定国家/地区启动单独的频道,根据负载我们可以切换同步方法等)。
这意味着,我们可能有 UpdateProductsForChannelAJob,它将用于两个不同的频道(ChannelA US 和 ChannelA UK),因此它的记录器将取决于它所依赖的频道。
所以我们现在要做的是为每个通道创建子记录器,并在解析作业实例时将其作为参数传递。这可行,但有一件烦人的事情 - 我们必须在作业中手动将记录器实例传递给每个依赖项(和依赖项依赖项),这可能正在记录一些东西。
更新 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"));
}
}
但事实并非如此。
【问题讨论】:
-
重新“寻找来自可靠和/或官方来源的答案。”我并不是要吹嘘或排除其他答案,但我目前是 Castle-windsor 标签stackoverflow.com/tags/castle-windsor/topusers 的最佳回答者,也是 Castle 团队的成员:castleproject.org/community/team.html
-
Mauricio,我毫不怀疑您的知识(实际上我正在使用 solrnet,它是一个极好的库),我的意思是,我确信应该有解决方案或至少有明确的解释我做错了什么。您的答案专门针对 ILogger,但我的问题是如何在解决时刻将具体实例传递给组合。对不起,如果这看起来像我不认为你是可信的或smth。我已经更新了最让我困惑的部分。
-
啊,现在更清楚了。之所以这样,是因为您实际上不应该将深层内联依赖项传递给 Resolve。您应该注册您的组件并让 Windsor 管理它们。问题是,为什么你不想注册你的组件?此外,如果这不是关于日志记录,请使用更合适的类比(或仅介绍您的具体案例)。
-
您能提供更多有关您的问题的信息吗?或者你能解决它吗?
-
用例子更新了问题,还没有解决。
标签: c# castle-windsor