はじめに
Unity と Policy Injection Application Block (以下 PIAB) と連携させてみました。
カスタム Callhandler とカスタム HandlerAttribute
[ConfigurationElementType(typeof(CustomCallHandlerData))]
public class EventLogCallHandler : ICallHandler
{
public int Order { get; set; }
public EventLogCallHandler(NameValueCollection attributes)
{
// このコンストラクタは必須みたい
}
private const string SOURCE = "PIABSample";
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
// メソッド呼び出し前にログを出力
EventLog.WriteEntry(SOURCE,
string.Format("{0} メソッドを呼び出します。", input.MethodBase.Name),
EventLogEntryType.Information);
// メソッド呼び出し
IMethodReturn result = getNext()(input, getNext);
// メソッド呼び出し後にログを出力
if (result.Exception != null)
{
// 例外が発生したとき
EventLog.WriteEntry(SOURCE,
string.Format("{0} メソッド呼び出しで例外が発生しました。", input.MethodBase.Name),
EventLogEntryType.Error);
}
else
{
EventLog.WriteEntry(SOURCE,
string.Format("{0} メソッドを呼び出しました。", input.MethodBase.Name),
EventLogEntryType.Information);
}
return result;
}
}
public class EventLogCallHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler()
{
return new EventLogCallHandler();
}
}
『PIAB で属性を使ってインターセプト対象メソッドを指定する』のエントリで作成したものを流用します。
DI で使用するインタフェースとクラスを用意
public interface IAnimal
{
// Cry メソッド呼び出し時にイベントログを出力する
[EventLogCallHandler]
void Cry();
}
public class Wankuma : IAnimal
{
public void Cry()
{
Console.WriteLine("クマ~");
}
}
public class Person
{
[Dependency]
public IAnimal Pet { get; set; }
public void CallPet()
{
Pet.Cry();
}
}
毎度おなじみのインタフェースとクラスです^^;
PIAB と Unity を連携させるために UnityContainerExtension を作成
ここからが本番。
public class EventLogExtension : UnityContainerExtension
{
protected override void Initialize()
{
// ここで登録した PolicyIjectionPolicy は次に登録する
// PolicyInjectionStrategy で使われます。
Context.Policies.SetDefault<IPolicyInjectionPolicy>(new PolicyInjectionPolicy(true));
// Unity がインスタンスを生成するパイプラインの PreCreation ステージで、
// PolicyInjectionStrategy の処理が実行されるように登録します。
Context.Strategies.AddNew<PolicyInjectionStrategy>(UnityBuildStage.PreCreation);
}
}
PolicyInjectionStrategy は登録した PolicyInjectionPolicy を使って、Unity が生成したインスタンスに PIAB のポリシーを適用します。つまり RealProxy の派生クラスでラップする。この辺りは『PIABの中身を見てみた』のエントリを見て下さい。
Strategies や Policies がどう利用されるのかについては、後でエントリにする予定です。
作成した UnityContainerExtension を使ったコードに修正
static void Main(string[] args)
{
// DI コンテナ取得
UnityContainer container = new UnityContainer();
// DI コンテナを拡張
container.AddNewExtension<EventLogExtension>();
// 型を登録
container.RegisterType<IAnimal, Wankuma>();
// インスタンスを取得
Person person = container.Resolve<Person>();
// ペットを呼び出す
person.CallPet();
Console.ReadLine();
}
作成した EventLogExtension を使って、UnityContainer を拡張しています。
このコードを実行すると、CallPet メソッド内で Cry メソッドが呼ばれる前後にイベントログが出力されます。
まとめ
Unity と PIAB の連携は、UnityContainer のインスタンス生成処理のパイプラインに、ポリシーを適用する処理を組み込むための UnityContainerExtension を作成することで実現可能です。