Замок Виндзор Странное поведение WTH внедрение и фабричный метод

StackOverflow https://stackoverflow.com/questions/4398101

Вопрос

Я использую Castle Windsor 2.5.1 в проекте ASP.NET MVC и использую инъекцию свойств для создания объекта, который, как я ожидаю, всегда будет доступен в классе базового контроллера. Я использую фабрику для создания этого объекта, однако, если в конструкторе есть ошибка, я вообще не получаю предупреждение от Виндзора, и это просто возвращает мой объект, но без введения свойства.

Это ожидаемое поведение, и если да, то как я могу вызвать ошибку, когда фабрика не может ничего вернуть?

Вот пример

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 - Поэтому, хотя это не вернуло мне класс с моей зависимостью, вкладываясь, он все еще пытается выпустить его.

Это было полезно?

Решение

Насколько я знаю, да, это предполагаемое поведение. Это не специфично для заводских методов, это работает так для всех дополнительных зависимостей обслуживания. Необязательные зависимости, которые бросают при разрешении, рассматриваются как нерезовируемые. Это определено в DefaultComponentActivator.obtainPropertyValue ()

Конечно, вы всегда можете переопределить активатор по умолчанию своим собственным, если хотите изменить это поведение.

Другие советы

А также вариант, предложенный Маурисио, также возможно создать объект для достижения ожидаемого поведения, как объяснено это Пример страницы о объектах.

Вот моя реализация, которая немного более краткая:

[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 есть новое прохладное дополнение, которое Диагностическая регистрация в контейнере.

Так что, если вы делаете это, например, в приложении ASP.NET MVC:

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

Вы можете перенаправить журналы, пойманные Windsor на ваш настроенный журнал Log4net.

Тип информации, которая в настоящее время регистрирует, включает в себя:

  • Когда Виндзор пытается разрешить дополнительную зависимость (например, инъекцию свойств), но сбой из -за исключения, исключение регистрируется.
  • При регистрации типа по соглашению и игнорируя его из -за существующей регистрации для этого типа, этот факт регистрируется.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top