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

ama*_*tar 8 c# castle-windsor ioc-container microkernel

我在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<IMyDependency>().UsingFactoryMethod(() => new MyDependency(false)).LifeStyle.Transient,
            Component.For<MyConsumer>().LifeStyle.Transient
        );

        var consumer = container.Resolve<MyConsumer>();

        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<IMyDependency>().UsingFactoryMethod(() => new MyDependency(true)).LifeStyle.Transient,
            Component.For<MyConsumer>().LifeStyle.Transient
        );

        Assert.Throws<Exception>(() => container.Resolve<MyConsumer>());
    }

    [Test]
    public void CreateWithError_WhatActuallyHappens() //Gives me back a consumer, but ignores MyDependency
    {
        var container = new WindsorContainer().Register(
            Component.For<IMyDependency>().UsingFactoryMethod(() => new MyDependency(true)).LifeStyle.Transient,
            Component.For<MyConsumer>().LifeStyle.Transient
        );

        var consumer = container.Resolve<MyConsumer>();

        Assert.IsNotNull(consumer);
        Assert.IsNull(consumer.MyDependency); //Basically fails silently!
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Mau*_*fer 5

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

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


ama*_*tar 5

除了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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后只需装饰任何属性,[NonOptional]如果存在构造问题,您将收到错误.