温莎城堡奇怪的行为与财产注入和工厂方法

我在ASP.NET MVC项目中使用Castle Windsor 2.5.1并使用属性注入来创建一个我期望在基本控制器类上始终可用的对象。 我正在使用工厂来创建这个对象,但是如果构造函数中有错误,我根本不会收到来自Windsor的警告,它只返回我的对象​​但没有注入属性。

这是预期的行为,如果是这样,当工厂无法返回任何内容时,如何引发错误?

这是一个例子

public class MyDependency : IMyDependency { public MyDependency(bool error) { if (error) throw new Exception("I error on creation"); } } public interface IMyDependency { } public class MyConsumer { public IMyDependency MyDependency { get; set; } } [TestFixture] public class ProgramTest { [Test] public void CreateWithoutError() //Works as expected { var container = new WindsorContainer().Register( Component.For().UsingFactoryMethod(() => new MyDependency(false)).LifeStyle.Transient, Component.For().LifeStyle.Transient ); var consumer = container.Resolve(); Assert.IsNotNull(consumer); Assert.IsNotNull(consumer.MyDependency); } [Test] public void CreateWithError_WhatShouldHappen() //I would expect an error since it can't create MyDependency { var container = new WindsorContainer().Register( Component.For().UsingFactoryMethod(() => new MyDependency(true)).LifeStyle.Transient, Component.For().LifeStyle.Transient ); Assert.Throws(() => container.Resolve()); } [Test] public void CreateWithError_WhatActuallyHappens() //Gives me back a consumer, but ignores MyDependency { var container = new WindsorContainer().Register( Component.For().UsingFactoryMethod(() => new MyDependency(true)).LifeStyle.Transient, Component.For().LifeStyle.Transient ); var consumer = container.Resolve(); Assert.IsNotNull(consumer); Assert.IsNull(consumer.MyDependency); //Basically fails silently! } } 

一个有趣的观察,如果我在我的MVC应用程序中使用它,我在调用ReleaseComponent时会收到来自Windsor的内部错误 – 所以即使它没有给我一个注入了我的依赖项的类,它仍然似乎尝试释放它。

据我所知,是的,这是预期的行为。 这不是特定于工厂方法的,它适用于所有可选服务依赖项。 解析时抛出的可选依赖项被视为不可解析。 这在DefaultComponentActivator.ObtainPropertyValue()中定义

当然,如果要更改此行为,可以始终使用自己的默认激活器覆盖默认激活器。

除了Mauricio建议的选项外,还可以创建一个工具来实现预期的行为,如本示例页面中有关设施的说明。

这是我的实现,稍微简洁一点:

 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class NonOptionalAttribute : Attribute { } public class NonOptionalPropertiesFacility : AbstractFacility { protected override void Init() { Kernel.ComponentModelBuilder.AddContributor(new NonOptionalInspector()); } } public class NonOptionalInspector : IContributeComponentModelConstruction { public void ProcessModel(IKernel kernel, ComponentModel model) { foreach (var prop in model.Properties.Where(prop => prop.Property.IsDefined(typeof (NonOptionalAttribute), false))) { prop.Dependency.IsOptional = false; } } } 

然后只使用[NonOptional]装饰任何属性,如果构造有问题,您将收到错误。

从Castle Windsor 3.2开始,新的一个很酷的补充是容器中的Diagnostic日志记录 。

因此,如果您在ASP.NET MVC应用程序中执行此操作:

 var logger = _container.Resolve(); ((IKernelInternal)_container.Kernel).Logger = logger; 

您可以将Windsor捕获的日志重定向到配置的log4net记录器。

当前记录的信息类型包括:

  • 当Windsor尝试解析可选依赖项(如属性注入)但由于exception而失败时,将记录exception。
  • 按惯例注册类型并由于该类型的现有注册而忽略它时,将记录此事实。