ASPNET 5依存注入(Dependency Injection)

7282 ワード

依存注入はずっとaspである.Netwebフレームワーク(Web API、SignalR and MVC)の不可欠な一部ですが、以前は、このフレームワークはそれぞれアップグレードされ、それぞれの依存注入の実現方式があり、KatanaプロジェクトがOwinを通じてこれらのプロジェクトを接続しようとしても、統一的なコンデンサでサポートしなければなりませんでしたが、今は事情が変わりました.
 
抽象
asp.Netチームは、最も流行しているIOCコンテナの中で最も核心的な機能を抽出し、異なるコンポーネントにこれらのインタフェースを実現させることで、依存注入機能を提供することにした.
 
 
IServiceProvider
 
この最も主要なインタフェース、開発はすべてこのインタフェースを通じてIoc容器の中ですでに登録したサービスを検索することができて、このインタフェースは1つの方法しかありません:
GetService(Type)はAotufactの
Container.Resolve、またはNinjectの
Kernel.Get.
    
すべてのMiddleWareには2つの方法があります
IserviceProvider.
  • アプリケーションレベル:HttpContext.ApplicationServicesプロパティはMiddleWare
  • に提供されます.
  • 要求レベル:HttpContext.RequestServicesプロパティはMiddleWareに提供されます.この範囲のServiceProviderは、最初のリクエスト管理チャネルで暗黙的なMIddleWareによって作成され、リクエストが最後に応答に戻る前に解放されます.

  •  
    すべてのMiddleWareは、ASPなどのサービスをこれらの属性で解決することができます.NET MVC MIddleWareが通過します
    RequestServicesはControllersと彼らの依存を作成します
     
    IServiceScope
     
    このインタフェースは容器の包装であり、主な役割は要求が終わった後に容器を解放することである.
  • IServiceProvider 
  • Dispose()

  •  
    IServiceScopeFactory
    簡単なインタフェースで、戻るのは1つだけです.
    IServiceScopeの方法
    CreateServiceScope()
     
    IOCコンテナを実現する必要がある場合は、以上のインタフェースを自分で実現する必要があります.
     
    ServiceLifetime
  • Singleton単一インスタンス
  • アプリケーション全体
  • Scoped単一インスタンス範囲ウィンドウ内
  •  
    ServiceDescriptor
    登録サービスの説明情報、
  • ServiceTypeは、特定の実装クラスのインタフェースを置き換えるために使用され、Typeタイプ
  • ImplementationType上のこのインタフェースの具体的な実装タイプ、Typeタイプ
  • Lifetimeサービスのライフサイクル、Singleon、ScopedまたはTransient
  • ImplementaionFactoryタイプFuncは、一部のシーンでは、開発者が特定の実装クラスを作成するためのファクトリメソッドを提供することを望んでいる.彼らは互いに独立しているので、もしあなたがImplementationTypeを提供したら、それはもうImpletentationFactoryを提供することはできません.
  • ImplementationInstance具体例
  •  
      Registering Services
    今あなたのサービスを登録して、ASPNET 5はあなたのを望みます
    Startupクラスには
    ConfigureServicesのメソッド名には、一連の
    ServiceDescriptorsパッケージ
    IServiceCollection、何も返さない.あなたがすべてするのは一連の作成だけです
    ServiceDescriptorをコレクションに追加すると、Webアプリケーションが後でロードされ、コンテナに登録されます.
     
    publicvoidConfigureServices(IServiceCollection services)
    {
        var serviceDescriptor = newServiceDescriptor(typeof(IBankManager), typeof(BankManager), ServiceLifetime.Transient);
        services.Add(serviceDescriptor);
     
        // Add MVC services to the services container.
        services.AddMvc();
    }

        
    コメント

    ServiceDescriptorの作成にはいくつかの煩わしさがあります.これは、「ServiceAddMvc()」のような拡張方法でServiceDescriptorを作成するミドルウェアを見ることです.
     
    次の擬似記述は、サービス起動とServiceProviderがどのように作成されたかを示し、対応するコードは
    HostingEngine.スタートで見つけた
    アプリケーションはどのように起動されますか.
  • Hosting engineは、ServiceDescriptorの集合オブジェクト
  • であるIServiceCollectionを作成します.
  • Hosting engineは、必要なサービス
  • をすべて追加します.
  • Hosting engineは、プログラムセットにStartupクラスがあり、ConfigureServicesメソッド
  • があることを確認します.
  • Hosting engineはこのメソッドをロードし、IServiceCollection
  • を渡します.
  • StartupクラスのConfigureSerivcesでは、アプリケーションに必要なサービスがセットの
  • に追加されます.
  • Hosting engineでは、DefaultServiceProvider(ICOコンテナ)が作成され、サービスセットのIServiceCollectionのサービス
  • が登録されます.
  • Hosting engineは、アプリケーションビルダー(IApplicationBuilder)を作成し、IApplicationBuilderに渡す.ApplicationServicesは、新しいサービスプロバイダを割り当て、さらに
  • を使用します.
  • Hosting enginはStartupにあります.Configuerが実行する前に、R e q u s t S e r v e s ContainerMiddlewareミドルウェアが作成されます.
  • については後述します.
  • Hosting engineは、Startupクラスのコンフィギュレーションメソッドを実行し、Application Builderを渡してミドルウェアを作成します.サービスプロバイダが必要な場合は、ApplicationServicesプロパティを使用してミドルウェアを作成できます.

  •  
     
    実行要求
    最初の要求が来ると、Httpcontextは作成され、最初のMiddlewareのInvokdeメソッドに渡され、Middleware全体に伝わる.しかし、最初のミドルウェアを処理する前に、Application Builder's Service ProviderはHttpContextに割り当てられる.ApplicationServicesでは、ミドルウェア全体がこの属性で必要なサービスを得ることができることを確認しますが、これはアプリケーションレベルのサービスプロバイダであり、選択したIocコンテナに依存していることを覚えておいてください.それを使用すると、アプリケーションのライフサイクル全体にオブジェクトが存在する可能性があります.
    Note: 
    Intheory、理論的には、アプリケーション開発者として、このサービスプロバイダを直接使用するべきではありません.もしサービスLocatorモードを推奨するならば.
     
    はい、これはアプリケーションレベルのサービスプロバイダですが、毎回要求範囲内のサービスプロバイダはありますか?
    上記の手順8では、Hosting engineがパイプの開始前に作成されることについて説明しました.
    RequestServices ContainerMiddlewareミドルウェアは、最初に実行されます.
    public async Task Invoke(HttpContext httpContext)
    {
        using(varcontainer = RequestServicesContainer.EnsureRequestServices(httpContext, _services))
        {
            await_next.Invoke(httpContext);
        }
    }

     
    上記の要求実行に戻ると、サービスはHttpcontextを作成し、Application-level Service ProviderにHttpContextを割り当てる.ApplicationServicesは、最初のミドルウェアを呼び出します.上のR e q u s t ServicesContainerMiddlewareです.これは、範囲内のサービスプロバイダを作成し、リクエストの終了時に破棄することです.
    その擬似実装は次のとおりです.
  • リクエストがRequestServiceContainerMiddlewareによって処理されている
  • Invokeメソッドでは、アプリケーションサービスプロバイダからIServiceScopeFactoryが作成されます.
  • IServiceScopeFactoryは、スコープコンテナ(scoped container)
  • を作成します.
  • scoped containerは属性HttpContextに割り当てられる.RequestServices
  • Invokeメソッド呼び出し次のMiddleware
  • すべてのMiddlewareが実行されると、RequestServiceContainerMiddlewareに戻り、Scoped ContainerはUsing
  • を介して破棄されます.
     
    Note: 
    RequestServices ContainerMiddlewareは、このパッケージ/ヘルプクラスRequestServices ContainerによってScoped Services Providerの作成と破棄を管理します.
     
    HttpContext.RequestServicesは、ライフサイクルを要求する範囲のサービスプロバイダです.その後、すべてのMiddleがアクセスできます.たとえば、MvcRouteHandlerを表示するとします.InvokeActionAsyncこれによってControllerを作成したことがわかります
     
    private async Task InvokeActionAsync(RouteContext context, ActionDescriptor actionDescriptor)
    {
        var services = context.HttpContext.RequestServices;
        Debug.Assert(services != null);
     
        var actionContext = new ActionContext(context.HttpContext, context.RouteData, actionDescriptor);
     
        var optionsAccessor = services.GetRequiredService<IOptions<MvcOptions>>();
        actionContext.ModelState.MaxAllowedErrors = optionsAccessor.Options.MaxModelValidationErrors;
     
        var contextAccessor = services.GetRequiredService<IScopedInstance<ActionContext>>();
        contextAccessor.Value = actionContext;
        var invokerFactory = services.GetRequiredService<IActionInvokerFactory>();
        var invoker = invokerFactory.CreateInvoker(actionContext);
        if (invoker == null)
        {
            LogActionSelection(actionSelected: true, actionInvoked: false, handled: context.IsHandled);
     
            throw new InvalidOperationException(
                Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(
                    actionDescriptor.DisplayName));
        }
     
        await invoker.InvokeAsync();
    }