web-dev-qa-db-ja.com

ASP.NET Web API 2.1を使用した依存関係注入の構成

ASP.NET Web API 2.1サイトを作成していますが、コントローラーに依存関係を直接挿入するため、IDependencyResolverの独自の実装を作成して、StructureMapで処理できるようにしました。

public class StructureMapDependencyResolver : IDependencyResolver
{
    public IDependencyScope BeginScope()
    {
        return this;
    }

    public object GetService(Type serviceType)
    {
        return ObjectFactory.GetInstance(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {            
        return ObjectFactory.GetAllInstances(serviceType).Cast<object>();
    }

    public void Dispose()
    {
    }
}

次に、Global.asaxのApplication_Startメソッドにこの行を追加して、このクラスを使用するようにWeb APIに指示しました

GlobalConfiguration.Configuration.DependencyResolver = new StructureMapDependencyResolver();

それはコンパイルされましたが、ブラウザでAPIメソッドのいずれかにアクセスしようとすると、このようなエラーが発生しました

No Default Instance defined for PluginFamily System.Web.Http.Hosting.IHostBufferPolicySelector, System.Web.Http

これは、StructureMap構成に行を追加したため、比較的簡単に解決できました

this.For<IHostBufferPolicySelector>().Use<WebHostBufferPolicySelector>();

しかし、その後、他のSystem.Web.Httpクラスに対して他の同様のエラーが発生し、それらのいくつかを解決することができましたが、そのうち3つ、つまりITraceManager、IExceptionHandler、IContentNegotiatorを処理する方法に固執しています。

問題は、ITraceManagerのデフォルト実装と思われるTraceManagerが内部クラスであるため、StructureMap構成で参照できないことです。

だから私はこれについて完全に間違った方法で行っていますか、またはこれらの内部クラスを注入する他の方法がありますか?

28
Paul Hunt

なぜこのようにしないのか、どうやって違うやり方をするのか、提案と説明をしたいと思います(私はもっと良くて適切に言います)。

不適切なIDependencyResolver設計の完全かつ完全な説明は、ここにあります。 ASP.NET Web APIを使用した依存性注入とライフタイム管理 by Mark Seemann

これらの重要な部分を引用させてください。

IDependencyResolverの問題

IDependencyResolverの主な問題は、本質的にService Locatorであることです。 Service Locatoranti-patternには多くの問題がありますが、それらのほとんどはすでにこのブログの他の場所(および私の本)で説明されています。 Service Locatorの短所の1つは、まだあまり説明していませんが、GetServiceを呼び出すたびにコンテキストがまったくないことです。これは、IDependencyResolverだけでなく、Service Locatorアンチパターンの一般的な問題です。

そしてまた:

...依存関係グラフは、コンテキストについて何かを知る必要があります。リクエストURLは何ですか?要求されたベースアドレス(ホスト名など)は何ですか?単一のリクエスト内で依存関係インスタンスを共有するにはどうすればよいですか?このような質問に答えるには、コンテキストについて知っておく必要があり、IDependencyResolverはこの情報を提供しません。

要するに、IDependencyResolverは依存関係グラフを作成するための正しいフックではありません。 **幸いなことに、ASP.NET Web APIには、この目的のための拡張ポイントがあります。 **

ServiceActivator

したがって、このシナリオでの答えはServiceActivatorです。この答えを見てください:

ServiceActivatorの例:

public class ServiceActivator : IHttpControllerActivator
{
    public ServiceActivator(HttpConfiguration configuration) {}    

    public IHttpController Create(HttpRequestMessage request
        , HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        var controller = ObjectFactory.GetInstance(controllerType) as IHttpController;
        return controller;
    }
}

StructureMapでできることはすべて整っています。 Web APIフレームワークの主要な機能はまだ残っています...それらをハックする必要はありません。また、むしろDI/IoCを使用してからサービスロケーターを使用しています

48
Radim Köhler