extraño comportamiento castillo de Windsor con la inyección de la propiedad y método de fábrica

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

Pregunta

Estoy utilizando el castillo de Windsor 2.5.1 en un proyecto ASP.NET MVC y usar la inyección de propiedad para crear un objeto que espero estar siempre disponible en una clase de controlador de base. Estoy utilizando una fábrica para crear este objeto, sin embargo, si hay un error en el constructor, no recibo una advertencia de Windsor en absoluto y sólo devuelve mi objeto, pero sin inyectar la propiedad.

Es este el comportamiento esperado, y si es así, ¿cómo puedo obtener produce un error cuando una fábrica no devuelve nada?

Este es un ejemplo

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

Una observación interesante, si uso esto en mi aplicación MVC, me sale un error interno de Windsor al llamar ReleaseComponent - así que, aunque no dio una clase ME volver con mi dependencia inyecta, todavía parece tratar de dejar la a él.

¿Fue útil?

Solución

Por lo que yo sé, sí, ese es el comportamiento previsto. Esto no es específico de métodos de fábrica, funciona igual que la de todas las dependencias de servicio opcional. dependencias opcionales que arrojan al resolver son tratados como no resoluble. Esto se define en DefaultComponentActivator.ObtainPropertyValue ()

Por supuesto, siempre se puede anular el activador del defecto con su propio si desea cambiar este comportamiento.

Otros consejos

Además de la opción sugerida por Mauricio, también es posible crear un Fondo para lograr el comportamiento esperado como se explica en esta página ejemplo sobre instalaciones.

Aquí está mi aplicación que es ligeramente más concisa:

[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;
        }
    }
}

A continuación, sólo decorar propiedades con [NonOptional] y usted recibirá un error si hay un problema con la construcción.

A partir del castillo de Windsor 3.2 hay una nueva adición de un fresco que es registro de diagnóstico en el recipiente .

Así que si usted hace esto, por ejemplo, en una aplicación ASP.NET MVC:

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

puede redirigir los registros capturados por Windsor a su registrador de log4net configurado.

El tipo de información que actualmente se está registrando incluye:

  • Cuando Windsor intenta resolver una dependencia opcional (como la inyección de la propiedad), pero falla debido a una excepción, se registra la excepción.
  • Cuando se registra un tipo de convenciones y haciendo caso omiso de ella debido a un registro ya existente para ese tipo, este hecho se registra.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top