【问题标题】:Castle Windsor strange behaviour wth property injection and factory methodCastle Windsor 属性注入和工厂方法的奇怪行为
【发布时间】:2011-05-22 20:05:23
【问题描述】:

我在 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!
    }
}

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

【问题讨论】:

    标签: c# castle-windsor ioc-container microkernel


    【解决方案1】:

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

    中定义的

    当然,如果你想改变这种行为,你总是可以用你自己的来覆盖默认的激活器。

    【讨论】:

    • 谢谢,答案就在眼前!我可以通过几种方式解决这个问题,所以这不是问题
    【解决方案2】:

    除了 Mauricio 建议的选项外,还可以创建一个 Facility 来实现预期的行为,如 this 有关设施的示例页面中所述。

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

    [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] 装饰任何属性,如果构造出现问题,您将收到错误消息。

    【讨论】:

    • 完美!如果有人不记得安装设施的语法(比如我),只需在引导例程期间调用 Container.AddFacility()
    【解决方案3】:

    从 Castle Windsor 3.2 开始,有一个很酷的新增功能是 Diagnostic logging in the container

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-17
      • 1970-01-01
      相关资源
      最近更新 更多