2010-12-09 87 views
8

我在ASP.NET MVC項目中使用Castle Windsor 2.5.1,並使用屬性注入來創建一個對象,我希望這個對象始終在基礎控制器類上可用。我使用工廠來創建這個對象,但是如果在構造函數中有錯誤,我根本沒有從Windsor得到警告,它只是返回我的對象​​,但沒有注入屬性。Castle 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時得到溫莎內部錯誤 - 所以即使它沒有給我回類與我的依賴注入,它仍然似乎嘗試釋放它。

回答

5

據我所知,是的,這就是預期的行爲。這不是特定於工廠方法的,它適用於所有可選的服務依賴關係。 將解析時拋出的可選依賴項視爲不可解析。 這是定義在DefaultComponentActivator.ObtainPropertyValue()

當然,如果你想改變這種行爲,你總是可以用你自己的默認激活器。

+1

謝謝,答案是現貨!我可以通過幾種方法解決這個問題,所以這不是問題 – amarsuperstar 2010-12-09 18:51:24

+1

這是一個解決方法:http://stackoverflow.com/a/12007547/114029 – 2014-01-08 21:19:53

5

除了Mauricio建議的選項外,還可以創建一個工具來實現預期的行爲,如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],如果有施工的問題,您會收到一個錯誤。

0

從溫莎城堡3.2開始,有一個很酷的新東西,就是Diagnostic logging in the container

所以,如果你在一個ASP.NET MVC應用程序做到這一點,例如:

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

可以重定向溫莎抓住你的配置log4net的記錄日誌。

的信息當前正在記錄的類型包括:

  • 當溫莎嘗試解析一個可選的依賴(如屬性注射),但一個例外由於失敗 ,異常記錄。
  • 當按照慣例註冊類型並由於該類型的現有註冊而忽略它時,會記錄此事實。