Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何配置windsor以通过依赖关系树传递依赖关系作为参数?_C#_Castle Windsor - Fatal编程技术网

C# 如何配置windsor以通过依赖关系树传递依赖关系作为参数?

C# 如何配置windsor以通过依赖关系树传递依赖关系作为参数?,c#,castle-windsor,C#,Castle Windsor,我有以下组成部分: 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 servic

我有以下组成部分:

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; }
}
正如您所看到的,到处都有记录器属性。问题是,我需要在解析过程中传递该属性值(不同的作业需要不同的配置记录器)。 所以,如果只有最上面的组件需要这个,它将像

var childLogger = Logger.CreateChildLogger(jobGroupName);
var job = windsorContainer.Resolve(jobType);
job.Logger = childLogger;
但我需要向下传递childLogger,而这棵树非常复杂,我不希望手动将logger实例传递给每个组件,每个组件都需要它,不知道Windsor是否可以在这方面帮助我

更新:这可能有助于更好地理解问题: 在通知中:

内联依赖项不会传播 您传递给Resolve方法的任何参数都只对根组件可用
您正在尝试解析,以及它的拦截器。所有向下的组件(根的 依赖项及其依赖项等)将无权访问它们

为什么会这样?有什么解决办法吗

更新2: 如果我加上真实的情况,也许会有帮助

因此,我们有一个应用程序,它从各个销售渠道发送/接收数据。每个销售渠道都有相应的作业集合,如发送更新的产品信息、接收订单等(每个作业中可能包含较小的作业)。因此,我们需要将每个通道的日志信息与其他通道的日志信息分开,这是合乎逻辑的,但是单个通道的作业日志应该放在单个侦听器中,这样我们可以看到发生的事情的顺序(如果每个作业和子作业都有自己的日志侦听器,我们需要按时间合并日志以了解发生了什么)。有些通道及其作业集在编译时是未知的(比如说有通道A,我们可以通过简单地将该国家添加到DB来启动特定国家的单独通道,根据负载我们可以切换同步方法等)

这意味着,我们可能有更新产品ForChannelaJob,它将在两个不同的频道(ChannelA US和ChannelA UK)中使用,因此它的记录器将取决于它所依赖的频道

所以我们现在要做的是,为每个通道创建子记录器,并在解析作业实例时将其作为参数传递。这是可行的,但有一件烦人的事情——我们必须在作业中手动将记录器实例传递给每个依赖项(和依赖项),这些依赖项可能会记录一些东西

更新3:

我在Windsor文档功能中发现了这一点,听起来像我需要的:

有时需要提供依赖项,直到组件创建时才知道。例如,假设您需要服务的创建时间戳。您知道如何在注册时获得它,但不知道它的具体值是什么(事实上,每次创建新实例时它都会有所不同)。在这种情况下,您将使用DynamicParameters方法

在DynamicParameters委托中有两个参数,其中一个是dictionary和

您现在可以使用依赖项填充该字典,这些依赖项将进一步传递到解析管道

有鉴于此,我认为这会奏效:

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"));
    }
}
公共接口iSeries设备
{
}
带有记录器的公共类服务:IService
{
公共ILogger记录器{get;set;}
}
公共类服务组合
{
公共ILogger记录器{get;set;}
公共IService服务{get;set;}
公共服务组合(iSeries服务)
{
服务=服务;
}
} 
公共类名称服务
{
公共名称服务(字符串名称)
{
名称=名称;
}
公共字符串名称{get;set;}
}
公共类名称服务消费者
{       
公共名称服务名称服务{get;set;}
}
公共类NameServiceConsumerComposition
{       
公共名称服务名称服务{get;set;}
公共名称ServiceConsumer名称ServiceConsumer{get;set;}
}
[测试夹具]
公开课考试
{
[测试]
public void given dynamicParameters配置containersouldpassloggerdownthetree()
{
var container=新的WindsorContainer();
container.AddFacility();
集装箱。登记(
Component.For().ImplementedBy().LifestyleTransient(),
Component.For().DynamicParameters((k,d)=>
{
d[“Logger”]=k.Resolve().CreateChildLogger(d[“name”].ToString());
}).生活方式
);
var service=container.Resolve(new{name=“my child”});
var childLogger=((ServiceWithLogger)service.service).Logger;
Assert.IsTrue(((ConsoleLogger)childLogger.Name.Contains(“我的孩子”));
}
[测试]
public void given dynamicParameters配置containersouldpassname down the tree()
{
var container=新的WindsorContainer();
container.AddFacility();
集装箱。登记(
Component.For().LifestyleTransient().DependsOn(新的{name=“default”}),
Component.For().LifestyleTransient(),
Component.For().DynamicParameters((k,d)=>
{
d[“nameService”]=k.Resolve(d[“nameParam”]);
}).生活方式
);
var service=container.Resolve(new{nameParam=“my child”});
WriteLine(service.NameServiceConsumer.NameService.Name);
Assert.IsTrue(service.NameServiceConsumer.NameService.Name.Contains(“我的孩子”);
}
}

但事实并非如此。

解析后,不要手动传递记录器。让温莎为你做吧。使用。

我想我终于明白了为什么这相对容易实现,但在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属性