はじめに
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 を作成することで実現可能です。