NinjectでInterceptorをつかう

Inteceptorの機能はExtensionとして提供されています。ダウンロードはここからできます。

インターセプタの実装が2つ(Castle DynamicProxyとLinFu)あるのでどちらか版を選ぶといいと思います。軽く調べた限りではCastleの方が信頼性があるっぽいので、Interception 2.0.0.0 .NET 3.5 Binaries with Castle DynamicProxy 2.2を使うことにします。

拡張メソッドを使ってNinjectのCore部分を拡張しているので、適切にusingしておかないと補完がききません。とりあえずこの3つを。

using Ninject;
using Ninject.Extensions.Interception;
using Ninject.Extensions.Interception.Infrastructure.Language;

インターセプトの対象。

public class Person
{
    public virtual void SayHello(string name)
    {
        Console.WriteLine("Hello {0}", name);
    }
}

SimpleInterceptorを継承すると簡単に作れます。ここではメソッドの呼び出し前後に適当にコンソール出力します。

public class TraceInterceptor : SimpleInterceptor
{
    protected override void BeforeInvoke(IInvocation invocation)
    {
        Console.WriteLine("Before");
    }
    protected override void AfterInvoke(IInvocation invocation)
    {
        Console.WriteLine("After");
    }
}

テストメソッド。LoadExtensions = falseにしておかないと勝手にモジュール読み込んでエラーになってしまうですよね。インターセプタのモジュールはDynamicProxy2Moduleを使います。

[TestMethod()]
public void InterceptorTest()
{
    var kernel = new StandardKernel(new NinjectSettings { LoadExtensions = false}, new DynamicProxy2Module());
    kernel.Bind<Person>().ToSelf().Intercept().With(new TraceInterceptor());
    var p = kernel.Get<Person>();
    p.SayHello("aaa");
}

実行結果

Before
Hello aaa
After

ここで、一番重要なのは、インターセプトの対象メソッドをvirtualにすること。こうしとかないとインターセプトされません。これに気づかなくてそーとう長いことはまりました。


作者のブログはここです。ドキュメントないよってコメントしたからか最近のエントリで使い方書いてくれました。