2010-12-09 10 views
8

Ich benutze Castle Windsor 2.5.1 in einem ASP.NET MVC-Projekt und mit Property-Injektion ein Objekt erstellen, die ich immer auf einer Basis-Controller-Klasse zur Verfügung stehen. Ich benutze eine Fabrik, um dieses Objekt zu erstellen, aber wenn es einen Fehler im Konstruktor gibt, bekomme ich von Windsor überhaupt keine Warnung und es gibt nur mein Objekt zurück, ohne die Eigenschaft zu injizieren.Castle Windsor seltsames Verhalten wth Property-Injektion und Factory-Methode

Ist dies das erwartete Verhalten, und wenn ja, wie bekomme ich einen Fehler, wenn eine Fabrik nichts zurückgibt? Hier

ist ein Beispiel

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

Eine interessante Beobachtung, wenn ich dies in meiner MVC-Anwendung verwenden, erhalte ich einen internen Fehler von Windsor, wenn ReleaseComponent Aufruf - so auch wenn es nicht mir gab zurück Klasse mit meiner Abhängigkeit injiziert, scheint es immer noch zu versuchen, es zu veröffentlichen.

Antwort

5

Soweit ich weiß, ja, das ist das beabsichtigte Verhalten. Dies ist nicht spezifisch für Factory-Methoden, es funktioniert wie für alle optionalen Service-Abhängigkeiten. Optionale Abhängigkeiten, die beim Auflösen ausgelöst werden, werden als nicht auflösbar behandelt. Dies ist definiert in DefaultComponentActivator.ObtainPropertyValue()

Natürlich können Sie den Standardaktivator immer mit Ihren eigenen überschreiben, wenn Sie dieses Verhalten ändern möchten.

+1

Danke, die Antwort ist genau richtig! Ich kann das auf verschiedene Arten umgehen, also ist das kein Problem – amarsuperstar

+1

Hier ist ein Weg um dies: http://StackOverflow.com/a/12007547/114029 –

5

Neben der von Mauricio vorgeschlagenen Option ist es auch möglich, eine Einrichtung zu erstellen, um das erwartete Verhalten zu erreichen, wie auf der Seite this über Einrichtungen erläutert.

Hier ist meine Implementierung, die etwas prägnanter ist:

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

Dann dekorieren nur alle Eigenschaften mit [NonOptional] und Sie erhalten eine Fehlermeldung erhalten, wenn es ein Problem mit dem Bau ist.

+1

Perfekt! Wenn sich jemand nicht an die Syntax zum Installieren von Einrichtungen erinnern kann (wie ich), rufen Sie einfach Container.AddFacility () während Ihrer Bootstrap-Routinen auf –

0

Ab Castle Windsor 3.2 gibt es eine neue Ergänzung, die Diagnostic logging in the container ist.

Also, wenn Sie dies tun, zum Beispiel in einem ASP.NET MVC-App:

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

Sie die von Windsor zu allen konfigurierten log4net Logger gefangen Protokolle umleiten.

Die Art der Informationen, die derzeit protokolliert umfasst:

  • Wenn Windsor versucht, eine optionale Abhängigkeit (wie Eigenschaft Injektion) zu lösen, aber nicht wegen einer Ausnahme, die Ausnahme protokolliert.
  • Beim Registrieren eines Typs nach Konvention und Ignorieren aufgrund einer bestehenden Registrierung für diesen Typ wird diese Tatsache protokolliert.
Verwandte Themen