しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET MVC 3 と LifetimeManager の関係

Unity を使うと事前に登録しておいたクラスは自動的にインジェクションが行われて非常に嬉しいのですが、Entity Framework で使う DbContext は複数インスタンスが作られると、変更追跡やトランザクション的な意味でよろしくないですよね。

そこで Unity にはインスタンスの生存期間を管理するために LifetimeManager という仕組みが用意されています。しかし、デフォルトでは毎回インスタンスを生成してしまうので、1 つの HTTP リクエストを処理している間はインスタンスを共有する LifetimeManager が必要になりますが、Unity にはそういった動作の LifetimeManager が用意されていません。

なので自分で用意する必要があるのですが、検索すると結構出てくるので安心です。今回は PerRequestLifetimeManager という名前で用意しました。

public class PerRequestLifetimeManager : LifetimeManager
{
    public PerRequestLifetimeManager()
    {
        _key = Guid.NewGuid();
    }

    private readonly Guid _key;

    public override object GetValue()
    {
        return HttpContext.Current.Items[_key];
    }

    public override void SetValue(object newValue)
    {
        HttpContext.Current.Items[_key] = newValue;
    }

    public override void RemoveValue()
    {
        HttpContext.Current.Items.Remove(_key);
    }
}

LifetimeManager は GetValue/SetValue/RemoveValue の 3 つを実装するだけです。ストレージとしては HttpContext の Items を使ってます。コンストラクタで Guid を作ることで、キーがユニークになるようにしてます。

これを RegisterType を呼ぶ時に引数で指定するだけです。

container.RegisterType<DbContext, UnitySampleDbContext>(new PerRequestLifetimeManager());

この場合だと UnitySampleDbContext は 1 リクエストで 1 つしか生成されなくなります。