キャッスルウィンザー奇妙な行動wthプロパティインジェクションと工場の方法
-
10-10-2019 - |
質問
ASP.NET MVCプロジェクトでCastle Windsor 2.5.1を使用しており、プロパティインジェクションを使用して、ベースコントローラークラスで常に利用できると予想されるオブジェクトを作成しています。私はこのオブジェクトを作成するために工場を使用していますが、コンストラクターにエラーがある場合、ウィンザーから警告がまったくありません。
これは予想される動作ですか、もしそうなら、工場が何も返さないときにエラーを発生させるにはどうすればよいですか?
これが例です
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アプリケーションでこれを使用すると、呼び出すときにWindsorから内部エラーが発生します ReleaseComponent
- そのため、依存関係を注入してクラスを返還しなかったとしても、リリースしようとするようです。
解決
私の知る限り、はい、それは意図した行動です。これは工場の方法に固有ではなく、すべてのオプションのサービス依存関係に対してそのように機能します。解決時に投げるオプションの依存関係は、解決不可として扱われます。これはで定義されています DefaultComponentactivator.obtainPropertyValue()
もちろん、この動作を変更したい場合は、デフォルトのアクティベーターを独自のアクティベーターで常にオーバーライドできます。
他のヒント
Mauricioが提案したオプションと同様に、説明されているように、予想される動作を達成するための施設を作成することもできます これ 施設に関する例のページ。
これが私の実装です。
[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]
建設に問題がある場合、エラーが発生します。
キャッスルウィンザー3.2の時点で、新しいクールな追加があります コンテナの診断ロギング.
したがって、たとえばASP.NET MVCアプリでこれを行う場合:
var logger = _container.Resolve<ILogger>();
((IKernelInternal)_container.Kernel).Logger = logger;
Windsorでキャッチされたログを構成されたLog4Netロガーにリダイレクトできます。
現在記録されている情報の種類には、以下が含まれます。
- Windsorがオプションの依存関係(プロパティインジェクションなど)を解決しようとするが、例外のために失敗すると、例外が記録されます。
- そのタイプの既存の登録のために、慣習ごとにタイプを登録し、それを無視する場合、この事実は記録されます。