開発部のM.Tです。
最近ASP.NET Coreのカスタムミドルウェアを作る機会がありました。
普段はコントローラの処理を実装することが多く、アプリケーションパイプラインやミドルウェアについて気にすることがあまりなかったのですが、やはりこの辺りの知識もアプリケーションを開発する上で大事だと感じたので学んだ内容を簡単にまとめようと思います。
ASP.NET Coreのミドルウェアとは
ASP.NET Coreのアプリケーションは受け取ったリクエストをコントローラで処理する前に、 ミドルウェアで構成されたパイプラインで処理していきます。 ミドルウェアには次の特徴があります。
- 各HTTPリクエストを処理できる
- パイプラインの次のミドルウェアの前後に処理を実行できる
- パイプラインの次のミドルウェアを呼び出すか、パイプラインをショートさせることができる
- Run, Map, Useの各拡張メソッドを使ってパイプラインに追加できる
- 匿名メソッドとしてin-lineで定義するか、再利用可能なクラスで定義することができる
例えばリクエストごとにログ出力したい場合、ログ出力用のミドルウェアを実装してパイプラインに追加すれば、 リクエストが来るたびにミドルウェアが実行され、ログが出力ができるようになります。
ミドルウェアの実行順
ミドルウェアはパイプラインに追加された順に実行されます。 ここで忘れてはいけないのが、上で挙げたミドルウェアの特徴「2. パイプラインの次のミドルウェアの前後に処理を実行できる」です。
Middleware1、Middleware2、Middleware3と順にパイプラインに追加していった場合、ミドルウェアの実行順序は下の図のようになります。

リクエストの処理はミドルウェアが追加された順に実行されていきますが、レスポンスはその逆順に処理が行われるんですね。
ミドルウェアの処理内容によっては、パイプラインのどこで実行するかが重要となります。 例えば例外処理のミドルウェアは、パイプライン処理の最後のほうの例外もキャッチできるよう、パイプラインの先頭に配置する必要があります。
ミドルウェアの実装を覗いてみる
ところで、「次のミドルウェアの前後に処理を実行できる」、これどうやって実装するのか気になりませんか? 実は驚くほどシンプルに実装できるようになっています。ミドルウェアのコードを見てみましょう。
public class MyMiddleware(RequestDelegate next) { protected readonly RequestDelegate _next = next; public virtual async Task InvokeAsync(HttpContext context) { // 次のミドルウェアの前の処理 await _next.Invoke(context); // 次のミドルウェアの後の処理 } }
コードを見ると、nextというパラメータがあります。 このnextパラメータは、パイプライン内の次のミドルウェアを表しています。 nextのInvoke()を呼べば次のミドルウェアに処理が移り、呼ばなければパイプライン処理をそこでショートさせることができます。 そしてコメントにあるように、次のミドルウェアの前後の処理はそれぞれnext.Invoke()の前後に書くだけでいいのです。 簡単ですね。
ミドルウェア間のデータの受け渡し
さて、あるミドルウェアで得た値を他のミドルウェアに渡したいこと、ありますよね。 コントローラで取得した値をミドルウェアに渡したい、あるいはその逆のケースもあると思います。
上のコードを見て分かるように、各ミドルウェアはHttpContextを受け取り、このHttpContextを使った操作を行います。 コントローラもHttpContextを受け取りますので、ミドルウェアと共有したい情報はHttpContextに載せることになります。
ここで使用するのが、HttpContext.Itemsプロパティです。 HttpContext.Itemsはキーと値のコレクションを取得・設定できるプロパティなので、 渡したい値を次のようにキーと値のペアで設定すれば、受け取る側はキーを指定して値を受け取ることができます。
HttpContext.Items["myKey"] = myValue;
こちらもとてもシンプルですね。
まとめ
今回業務でやりたかったことは上の内容でだいたいカバーできました。 面白いことに、一度ミドルウェアを自分で実装したら、その後の業務で他のミドルウェアを見たり触ったりする機会が増えました。
知識が増えると、視野も広がっていいですね。
ミドルウェアについては公式ドキュメントに実装方法などもっと詳しく書いてあるので、興味を持った方は読んでみてください。
おわりに
KENTEMでは、様々な拠点でエンジニアを大募集しています! 建設×ITにご興味頂いた方は、是非下記のリンクからご応募ください。 recruit.kentem.jp career.kentem.jp