3

次のコードを書くのは普通ですか?

protected void Application_BeginRequest()
{
    var container = new UnityContainer()
        .RegisterType<IUnitOfWork, MyEntities>()

    HttpContext.Current.Items["container"] = container;

    ServiceLocator.SetLocatorProvider(
        () => new UnityServiceLocator(container));
}

protected void Application_EndRequest()
{
    var container = HttpContext.Current.Items["container"] 
        as UnityContainer;

    if (container != null)
    {
        container.Dispose();
    }
}

または、すべてのリクエストの依存関係を登録するのは悪い習慣ですか?

ありがとう。

4

1 に答える 1

5

注: 次のアドバイスはすべての IoC フレームワークに当てはまり、Unity に固有のものではありません。

TLDR : これをしないでください。コンテナーを一度登録し、一度だけApplication_Start呼び出しますServiceLocator.SetLocatorProvider

「リクエストごと」または「Web リクエストごと」の有効期間を持つように依存関係を登録しても問題ありません。ただし、Web リクエストごとに新しいコンテナー インスタンスを作成することは、非常に悪い習慣です。

コンテナーは、(登録用ではなく) インスタンスの解決用に最適化されています。これは、(コンテナーから) 型が初めて要求されたときに、内部で動的コード生成が行われることが多いことを意味します。登録とコード生成およびコンパイル プロセスはかなり時間がかかる可能性があり、Web 要求ごとにコンテナーの新しいインスタンスを作成すると、完全な登録とコード生成プロセスが最初からやり直されます。これには時間がかかり、多くの一時オブジェクトが生成され (より多くのガベージが収集されます)、少なくともそのコンテナー インスタンスの存続期間中にキャッシュする必要がある新しいコードが生成されます。

さらに、複数のコンテナー インスタンスがあると、Web 要求ごとよりも大きなスコープでインスタンスを登録するなど、他の最適化を行うことが難しくなります。あなたの場合、タイプを「シングルトン」として登録することは、そのタイプがそのコンテナインスタンスのコンテキスト内でシングルトンであるため、実際には「Webリクエストごと」を意味します。または、パフォーマンスを考慮しなくても、一部の型が正しく機能するには、「Web 要求ごと」よりも長い有効期間 (アプリ ドメインごとに 1 つのインスタンスなど) が必要になり、構成が難しくなります。

リクエストごとにコンテナーを使用しても、おそらくこれを行うことができますが、コードの保守ははるかに困難になります。

コンテナー自体はスレッドセーフであるため、その意味では、要求ごとにコンテナー インスタンスを用意する必要はありません。

そして、あなたの場合、リクエストごとに変更するため、コードに競合状態同時実行バグがあるため、さらに悪いことです。ServiceLocatorServiceLocator、登録されたデリゲートをプライベートな静的フィールドに格納します。これは、すべてのスレッドからアクセスできることを意味します。つまり、ウェブ リクエストを介してコンテナ インスタンスを共有しています。一度に 1 つの Web リクエストが発生するため、開発中にはおそらく気付かないでしょうが、コード呼び出しServiceLocator.Currentがある場合、本番環境では失敗します。たとえば、リクエスト 1 が開始され、サービス ロケータが設定される次の非常に可能性の高いシナリオを考えてみましょう。その後、リクエスト 2 が開始され、独自のコンテナー インスタンスでサービス ロケーターがオーバーライドされます。その後、リクエスト 1 のコードが呼び出されますServiceLocator.Currentこれで、2 番目のリクエストのコンテナーが返されます。時々(運が良ければ)ObjectDisposedException. これは、別のスレッドがまだ (誤って) 使用しているコンテナーをスレッドが破棄した場合に発生します。ただし、別の Web リクエスト (複数のスレッドで使用するのは安全ではないインスタンス) に属する型が解決されることがあります。DataContextたとえば、LINQ to SQLまたは Entity Frameworkインスタンスを返す場合ObjectContextなどです。これらのクラスは通常、Web リクエストごとに構成する必要があり、複数のスレッドで共有することはできません

于 2012-08-28T12:36:51.543 に答える