2010-12-09 10 views
8

Estoy usando Castle Windsor 2.5.1 en un proyecto ASP.NET MVC y uso de inyección de propiedad para crear un objeto que espero siempre esté disponible en una clase de controlador base. Estoy usando una fábrica para crear este objeto, sin embargo, si hay un error en el constructor, no recibo ninguna advertencia de Windsor y simplemente devuelve mi objeto pero sin inyectar la propiedad.Castle Windsor comportamiento extraño con inyección de propiedad y método de fábrica

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

Aquí 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 me dio vuelta una clase con mi dependencia inyectada, todavía parece intentar liberarlo.

Respuesta

5

Hasta donde yo sé, sí, ese es el comportamiento previsto. Esto no es específico de los métodos de fábrica, funciona así para todas las dependencias de servicio opcionales. Las dependencias opcionales que se lanzan al resolver se tratan como no resolubles. Esto se define en DefaultComponentActivator.ObtainPropertyValue()

Por supuesto, siempre puede anular el activador predeterminado con el suyo si desea cambiar este comportamiento.

+1

¡Gracias, la respuesta es perfecta! Puedo solucionar esto de varias maneras, así que no hay problema – amarsuperstar

+1

Aquí hay una forma de evitar esto: http://stackoverflow.com/a/12007547/114029 –

5

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

Aquí es 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 cualquier propiedades con [NonOptional] y usted recibirá un error si hay un problema con la construcción.

+1

¡Perfecto! Si alguien leyendo no puede recordar la sintaxis para instalar instalaciones (como yo), simplemente llame a Container.AddFacility () durante sus rutinas de arranque –

0

A partir de Castle Windsor 3.2 hay una nueva y genial adición que es Diagnostic logging in the container.

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, la excepción se registra.
  • Al registrar un tipo por convenio e ignorarlo debido a un registro existente para ese tipo, este hecho se registra.
Cuestiones relacionadas