ASP.NET 5ベースのミドルウェア

10260 ワード

ソースhttps://docs.asp.net/en/latest/fundamentals/middleware.html
httpリクエストパイプに統合できるいくつかの小さなアプリケーションコンポーネントは、ミドルウェアと呼ばれます.ASP.NET 5はミドルウェアを統合してサポートし、アプリケーションのコンフィギュレーション方法でミドルウェアを構成することができます.

ミドルウェアとは


ミドルウェアは、要求および応答を処理するために使用できるアプリケーション要求パイプに組み込まれるコンポーネントです.各ミドルウェアは、要求をパイプ内の次のコンポーネントに渡すかどうかを判断したり、次のコンポーネントの前または後にいくつかの操作を実行したりすることができます.Request delegatesは、リクエストパイプを構築し、アプリケーションへのリクエストを処理するために使用されます.
Request delegatesは、IApplicationBuilderタイプのRun,Map,Use拡張メソッドによって構成され、IApplicationBuilderはStartupクラスでConfigureメソッドに渡される.request delegateは、埋め込まれた匿名の方法であってもよいし、服用可能なクラスに定義されていてもよい.この服用可能なクラスはミドルウェアであり、パイプ内の各ミドルウェアはinvokeパイプ内の次のミドルウェアを担当するか、適切な場合、間の短絡パイプ内のrequest delegateチェーン(直接戻る)を担当する.

IApplicationBuilderによるミドルウェアパイプの作成


ASP.NETリクエストパイプは、一連のリクエストエージェント(request delegate)からなり、次々と呼び出される.下図に示すように、黒い矢印は実行スレッドを示します.
各エージェントは、次のエージェントの前後でいくつかの操作を実行できます.いずれのエージェントも、リクエストを次のエージェントに転送するか、自分で処理するかを選択できます.直接処理は短絡実行パイプであり、場合によっては無駄な操作を回避することができる.たとえば、認可コンポーネントは、認可が通過した場合に次のコンポーネントにリクエストを転送したり、認可されていない場合に直接未認可を返したりすることができます.また、後続のコンポーネントチェーンから放出された例外をキャプチャするために、パイプの前方で呼び出される例外処理コンポーネントもあります.デフォルトのWebテンプレートでは、リクエストエージェントでパイプを構成する例を見ることができます.まずwire upエラーページ(in development)やWebサイトの本番環境をサポートするerror handlerを構築し、static files,ASPを構築します.NET Identity authentication, and finally, ASP.NET MVCのパイプ.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        app.UseBrowserLink();
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());

    app.UseStaticFiles();

    app.UseIdentity();

    // To configure external authentication please see http://go.microsoft.com/fwlink/?LinkID=532715

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

パイプラインは順次構築されているため、生産環境下ではUseExceptionHandlerがパイプラインの前面に配置されているため、パイプライン上で後で呼び出されるコンポーネントから放出される異常をキャプチャすることができる.また、ここでは、UseStaticFilesは、UseIdentityの前に構成されているので、静的ファイルは認証を許可する必要がなく、パフォーマンスを向上させることができます(ASP.NET 5では静的ファイルはいずれもwwwrootであり、デフォルトではアクセス可能であり、許可コンポーネントを実行する必要はありません).非静的ファイルとのリクエストは、パイプ内の次のコンポーネントにフローできます.Learn more about Working with Static Files.
Note:Configureメソッドで構成されているミドルウェアUse[Middleware]は,順序が重要である.
最も簡単なASP.NETアプリケーションは、すべてのリクエストを処理するためにリクエストエージェントを設定します.この場合、すべてのリクエストを処理する匿名関数が1つしかないため、「真の」リクエストパイプはありません.
app.Run(async context =>
{
    await context.Response.WriteAsync("Hello, World!");
});

ここで重要なのは、上記のようなリクエストエージェントが他のAppがあるかどうかにかかわらず、パイプを終了することです.Run呼び出し.次の例では、最初のエージェントのみが呼び出されます.
public void Configure(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Hello, World!");
    });

    app.Run(async context =>
    {
        await context.Response.WriteAsync("Hello, World, Again!");
    });

next呼び出しにより、パイプ内の次のリクエストエージェントを表す複数のrequestエージェントをリンクできます.次の例に示すように、nextを呼び出したが、次のリクエストエージェントの前または後に操作を実行できないという意味ではないことに注意してください.
public void ConfigureLogInline(IApplicationBuilder app, ILoggerFactory loggerfactory)
{
    loggerfactory.AddConsole(minLevel: LogLevel.Information);
    var logger = loggerfactory.CreateLogger(_environment);
    app.Use(async (context, next) =>
    {
        logger.LogInformation("Handling request.");
        await next.Invoke();
        logger.LogInformation("Finished handling request.");
    });

    app.Run(async context =>
    {
        await context.Response.WriteAsync("Hello from " + _environment);
    });
}

警告:Be wary of modifying HttpResponse after invoking next,since one of the components further down the pipeline may have written to the response,causing it to be sent to the client.(invoke nextの後にHttpResponseを変更しないでください.パイプの後ろのコンポーネントがresponseに書き込まれている可能性があります)Note:環境がLogInlineに設定されているため、ConfigureLogInlineメソッドは実行時に呼び出されます.詳細はWorking with Multiple Environments.残りの記事では、コンフィギュレーション[Environment]を使用して異なるオプションを表示できます.最も簡単なサンプルの実行方法は、projectでwebコマンドを使用することです.jsonで構成されています.
上記の例ではawait next.Invoke()は、プログラムを14行目に進め、クライアントは「Hello from LogInline」という応答を受信し、サーバコンソールは、以下のようにコンポーネントの前後のメッセージを出力します.

Run, Map, and Use


配管は、拡張方法Run,Map,and Useによって構成することができる.規則に従ってRunはパイプにミドルウェアを簡単に追加する方法であり、他の残りのミドルウェアは呼び出されない.だからRunはパイプの最後に呼び出されるべきだ.RunはいくつかのミドルウェアがそのRun[Middleware]メソッドを露出することを約束しており,これらのメソッドはパイプの末端でのみ呼び出されるべきである.次の例(oneusing Run and the other Use)は、nextメソッドが2番目に呼び出されないため、等価である.
public void ConfigureEnvironmentOne(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Hello from " + _environment);
    });
}

public void ConfigureEnvironmentTwo(IApplicationBuilder app)
{
    app.Use(next => async context =>
    {
        await context.Response.WriteAsync("Hello from " + _environment);
    });
}

Note:IApplicationBuilderインタフェース自体がUseメソッドを暴露しているので、技術的には拡張メソッドばかりではありません.Useの例については、いくつか見てきました.**Map*拡張メソッドはbranching the pipelineの約束です.現在のインプリメンテーションでは、リクエストパスに基づくブランチおよび使用断言**がサポートされています.Map拡張方法は、要求パスに基づいて要求エージェントをマッチングするために使用することができる.Mapは、パスと個別のミドルウェアを構成するパイプの関数のみを受け入れます.次の例では、ルートパスが/base pathのリクエストは、HandleMapTestメソッドで構成されたパイプで処理されます.
private static void HandleMapTest(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test Successful");
    });
}

public void ConfigureMapping(IApplicationBuilder app)
{
    app.Map("/maptest", HandleMapTest);

}

Note:Mapを使用すると、各リクエストに対して一致するpath segmentがHttpResponseから取得する.Pathから削除し、HttpRequestに追加する.PathBase.
パスベースのマッチングに加えて、MapWhenは断言ベースのパイプ分岐をサポートし、柔軟なseperateパイプの構築を実行します.Funcを満たす任意の断言は、mapを新しいパイプに要求するために使用できます.次の例では、要求パラメータbranchをチェックするための簡単な断言
private static void HandleBranch(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Branch used.");
    });
}

public void ConfigureMapWhen(IApplicationBuilder app)
{
    app.MapWhen(context => {
        return context.Request.Query.ContainsKey("branch");
    }, HandleBranch);

    app.Run(async context =>
    {
        await context.Response.WriteAsync("Hello from " + _environment);
    });
}

この例では、断言を満たす要求は、HandleBranchに定義されたパイプによって処理されます.他のリクエストは、17行の定義されたエージェントで処理されます.

Built-in middleware(内蔵ミドルウェア)


ASP.NET内には以下のようなミドルウェアが付属しています
Middleware
Description
Authentication
Provides authentication support.
CORS
Configures Cross-Origin Resource Sharing.
Diagnostics
Includes support for error pages and runtime information.
Routing
Define and constrain request routes.
Session
Provides support for managing user sessions.
Static Files
Provides support for serving static files, and directory browsing.

Writing middleware(ミドルウェアの作成)


追加の要求処理関数については、コンフィグで呼び出すことができるIApplicationBuilderの拡張方法を暴露することによって、個別のクラスを使用してミドルウェアを構築することを推奨します.以前の簡単なloggingミドルウェアを別のクラスに変換し,RequestDelegateをコンストラクタパラメータとしてInvokeメソッドを以下のようにサポートした.
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.Framework.Logging;
using System.Threading.Tasks;

namespace MiddlewareSample
{
    public class RequestLoggerMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger _logger;

        public RequestLoggerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
        {
            _next = next;
            _logger = loggerFactory.CreateLogger<RequestLoggerMiddleware>();
        }

        public async Task Invoke(HttpContext context)
        {
            _logger.LogInformation("Handling request: " + context.Request.Path);
            await _next.Invoke(context);
            _logger.LogInformation("Finished handling request.");
        }
    }
}

ミドルウェアはExplicit Dependencies Principleに従います.コンストラクタを介してすべての依存性を暴露した.ミドルウェアは、以下のように依存するサービスを直接注入するために、UseMiddleware拡張を利用する.注入に依存するサービスは自動的に充填され、the extension takes a params array of arguments to be used for non-injected parametersである.
public static class RequestLoggerExtensions
{
    public static IApplicationBuilder UseRequestLogger(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestLoggerMiddleware>();
    }
}

拡張メソッドと関連するミドルウェアクラスを使用して、Configureメソッドの読み取り可能性を向上させます.
public void ConfigureLogMiddleware(IApplicationBuilder app,
    ILoggerFactory loggerfactory)
{
    loggerfactory.AddConsole(minLevel: LogLevel.Information);

    app.UseRequestLogger();

    app.Run(async context =>
    {
        await context.Response.WriteAsync("Hello from " + _environment);
    });
}

RequestLoggerMiddlewareにはコンストラクタパラメータILoggerFactoryが必要ですが、StartupクラスとUseRequestLogger拡張メソッドは明示的に提供されていません.しかし,UseMiddleware内の依存注入動作により自動的に提供される.Testing the middleware (by setting the ASPNET_ENV environment variable to LogMiddleware) should result in output like the following (when using WebListener):
Note:もう1つの例は、必要なコンストラクタパラメータを使用してStaticFileMiddlewareを作成するUseStaticFiles拡張メソッドです.この例では、StaticFileOptionsパラメータは伝達され、他のコンストラクタパラメータはUseMiddleware依存注入によって提供される.

Summary


Middleware provide simple components for adding features to individual web requests. Applications configure their request pipelines in accordance with the features they need to support, and thus have fine-grained control over the functionality each request uses. Developers can easily create their own middleware to provide additional functionality to ASP.NET applications.