Dependency injection Windsor Castle为给定服务提供多个组件

Dependency injection Windsor Castle为给定服务提供多个组件,dependency-injection,inversion-of-control,castle-windsor,Dependency Injection,Inversion Of Control,Castle Windsor,我有一个ILog接口和两个可能的实现:控制台日志和文件日志。我在MVC应用程序中使用Windsor Castle,因此我在controller安装程序中有以下代码: container.Register( Component.For<ILogFactory>().ImplementedBy<LogFactory>().Named("first").OnCreate(x => x.initialize(LogType.Console, null

我有一个ILog接口和两个可能的实现:控制台日志和文件日志。我在MVC应用程序中使用Windsor Castle,因此我在controller安装程序中有以下代码:

container.Register(
            Component.For<ILogFactory>().ImplementedBy<LogFactory>().Named("first").OnCreate(x => x.initialize(LogType.Console, null)).LifestyleSingleton(),
            Component.For<ILogFactory>().ImplementedBy<LogFactory>().Named("second").OnCreate(x => x.initialize(LogType.File, null)).LifestyleSingleton(),
            Component.For<ILog>().UsingFactoryMethod(kernel => kernel.Resolve<ILogFactory>("first").GetLog(LogType.Console)).Named("first_log").LifestyleSingleton(),
            Component.For<ILog>().UsingFactoryMethod(kernel => kernel.Resolve<ILogFactory>("second").GetLog(LogType.File)).Named("second_log").LifestyleSingleton()
        );

我想知道我如何才能决定注入名为first_log或second_log的ILog,抱歉响应太晚

您可以使用子依赖项解析器。它允许您为另一个组件的依赖项解析特定组件。下面的代码应该(未测试)基于TestController构造函数中的参数名称解析ILog。 因此TestController(ILog first)将解析名为first的ILog

class SubDepResolver : ISubDependencyResolver
{
  private IKernel kernel;
  SubDepResolver(IKernel kernel)
  {
    this.kernel = kernel;
  }

  public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
    DependencyModel dependency)
  {
    if (model.GetComponentType() != typeof(TestController)) return false;
    if (dependency.GetComponentType() != typeof(ILog)) return false;
    return true;
  }

  public object Resolve(
    CreationContext context, 
    ISubDependencyResolver contextHandlerResolver, 
    ComponentModel model,
    DependencyModel dependency)
  {
    var handlers = kernel.GetHandlers(typeof(ILog));
    var handler = handlers.Single(h => h.GetComponentName() == dependency.DependencyKey);
    return handler.Resolve(context);
  }
}
使用以下命令添加冲突解决程序:

container.Kernel.Resolver.AddSubResolver(new SubDepResolver(container.Kernel));
祝你好运,
Marwijn.

很抱歉回复太晚

您可以使用子依赖项解析器。它允许您为另一个组件的依赖项解析特定组件。下面的代码应该(未测试)基于TestController构造函数中的参数名称解析ILog。 因此TestController(ILog first)将解析名为first的ILog

class SubDepResolver : ISubDependencyResolver
{
  private IKernel kernel;
  SubDepResolver(IKernel kernel)
  {
    this.kernel = kernel;
  }

  public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
    DependencyModel dependency)
  {
    if (model.GetComponentType() != typeof(TestController)) return false;
    if (dependency.GetComponentType() != typeof(ILog)) return false;
    return true;
  }

  public object Resolve(
    CreationContext context, 
    ISubDependencyResolver contextHandlerResolver, 
    ComponentModel model,
    DependencyModel dependency)
  {
    var handlers = kernel.GetHandlers(typeof(ILog));
    var handler = handlers.Single(h => h.GetComponentName() == dependency.DependencyKey);
    return handler.Resolve(context);
  }
}
使用以下命令添加冲突解决程序:

container.Kernel.Resolver.AddSubResolver(new SubDepResolver(container.Kernel));
祝你好运,
Marwijn.

我找到了解决方案。TestController需要定义2个ILOG:

public class TestController : Controller 
{ 
private ILog log1; 
private ILog log2; 

public TestController(ILog _log1, ILog _log2) 
{ 
log1 = _log1; 
log2 = _log2; 
identifier = _identifier; 
}
然后有必要添加:

container.Register(
Component.For<MyController>().DependsOn(
 ServiceOverride.ForKey("_log1").Eq("first_log"),
 ServiceOverride.ForKey("_log2").Eq("second_log")).LifestyleTransient()
 );
container.Register(
Component.For().DependsOn(
ServiceOverride.ForKey(“\u log1”).Eq(“第一个日志”),
ServiceOverride.ForKey(“\u log2”).Eq(“第二个日志”).LifestyleTransient()
);
替换实际默认内容:

container.Register(
 Classes.
 FromThisAssembly().
 BasedOn<IController>().
 If(c => c.Name.EndsWith("Controller")).
 LifestyleTransient());
container.Register(
上课。
来自此程序集()。
BasedOn()。
If(c=>c.Name.EndsWith(“控制器”))。
生活方式(暂时的);

我找到了解决方案。TestController需要定义2个ILOG:

public class TestController : Controller 
{ 
private ILog log1; 
private ILog log2; 

public TestController(ILog _log1, ILog _log2) 
{ 
log1 = _log1; 
log2 = _log2; 
identifier = _identifier; 
}
然后有必要添加:

container.Register(
Component.For<MyController>().DependsOn(
 ServiceOverride.ForKey("_log1").Eq("first_log"),
 ServiceOverride.ForKey("_log2").Eq("second_log")).LifestyleTransient()
 );
container.Register(
Component.For().DependsOn(
ServiceOverride.ForKey(“\u log1”).Eq(“第一个日志”),
ServiceOverride.ForKey(“\u log2”).Eq(“第二个日志”).LifestyleTransient()
);
替换实际默认内容:

container.Register(
 Classes.
 FromThisAssembly().
 BasedOn<IController>().
 If(c => c.Name.EndsWith("Controller")).
 LifestyleTransient());
container.Register(
上课。
来自此程序集()。
BasedOn()。
If(c=>c.Name.EndsWith(“控制器”))。
生活方式(暂时的);

一个单元测试通常有1个被测试的类和0到多个伪类(mock或stub)。您不测试DI配置——这是应用程序的一部分——通常您不使用带有单元测试的DI容器。那么,假设
TestController
是一个模拟的,那么在这个场景中被测试的类是什么?如果您正在测试一个特定的记录器或特定的日志工厂,您应该在测试中使用
new
关键字创建它的实例。这不是单元测试:我只是将控制器命名为TestController,但您可以将其称为myController或任何您想要的名称。我只是想知道,在这个控制器中,我如何根据日志的名称来处理我想要注入的日志当涉及到日志记录时,更常见的是日志记录组件(
ILog
)的单个实现,配置用于在运行时确定它应该记录在哪里-文件、控制台、数据库、,etc-以及在什么级别-调试、警告、错误等,允许您在不重新编译代码的情况下更改日志配置。Log4net就是一个很好的例子。谢谢,实际上这个例子可能有点误导;我使用了一个日志示例,但目标有点不同,即:如何注入控制器,基于其名称的接口。。。这仍然是我无法处理的问题。我看不到您的TestController在Register方法中的注册。你能添加它吗?一个单元测试通常有1个被测试的类和0到许多假类(mock或stub)。您不测试DI配置——这是应用程序的一部分——通常您不使用带有单元测试的DI容器。那么,假设
TestController
是一个模拟的,那么在这个场景中被测试的类是什么?如果您正在测试一个特定的记录器或特定的日志工厂,您应该在测试中使用
new
关键字创建它的实例。这不是单元测试:我只是将控制器命名为TestController,但您可以将其称为myController或任何您想要的名称。我只是想知道,在这个控制器中,我如何根据日志的名称来处理我想要注入的日志当涉及到日志记录时,更常见的是日志记录组件(
ILog
)的单个实现,配置用于在运行时确定它应该记录在哪里-文件、控制台、数据库、,etc-以及在什么级别-调试、警告、错误等,允许您在不重新编译代码的情况下更改日志配置。Log4net就是一个很好的例子。谢谢,实际上这个例子可能有点误导;我使用了一个日志示例,但目标有点不同,即:如何注入控制器,基于其名称的接口。。。这仍然是我无法处理的问题。我看不到您的TestController在Register方法中的注册。你能加上它吗?