ASP.NET Core でも UseStatusCodePages
を使えば 400-599 のステータスコードの場合に、専用のページを表示できることを前に書きました。最低限必要な機能はちゃんと揃っています。
しかし UseStatusCodePages
を使って対応できるのは、ステータスコードを URL フォーマットとして埋め込んで、後はコントローラ側に任せるという形です。
IIS や ASP.NET ではあったステータスコード単位でページを指定する方法は、そのままでは使えません。必要かどうかはともかくとして、今回は必要なケースがあったので対応してみました。
アクションにステータスコードを埋め込む
割とすぐに思いつく方法は、アクション名をそのままステータスコードにしてしまうことでしょう。メソッド名として 404 などは書けないですが、ルーティングレベルでは書けます。
[Route("[controller]")] public class ErrorController : Controller { [Route("404")] public IActionResult NotFound() { return View(); } [Route("500")] public IActionResult ServerError() { return View(); } }
上のようなコントローラを用意すれば、後は Startup
で設定するだけです。
app.UseStatusCodePagesWithRedirects("~/Error/{0}");
これで実行すると、ちゃんと存在しないページにアクセスした場合に 404 ページが表示されます。
一応これで目的は果たせますが、指定外のステータスコードの扱いがちょっと面倒です。
Middleware レベルで振り分ける
ルーティングレベルで解決するのもアレだったので、もう一つ UseStatusCodePages
に用意されているオーバーロードを使って解決してみることにしました。
オーバーロードには HttpContext
に触れるものがあるので、そこでステータスコードを見てリダイレクト先を変更するという方法です。以下のようなコントローラを用意します。
[Route("[controller]/[action]")] public class ErrorController : Controller { public IActionResult NotFound() { Response.StatusCode = 404; return View(); } public IActionResult ServerError() { Response.StatusCode = 500; return View(); } }
MVC 5 時代からありそうなコントローラです。ステータスコードを返すのに TrySkipIisCustomErrors = true
を使う必要がなくなったのは地味に嬉しいと感じるポイントです。
そして Startup
ではステータスコードを見てリダイレクト先を変えるコードを書きます。
app.UseStatusCodePages(context => { if (context.HttpContext.Response.StatusCode == 404) { context.HttpContext.Response.Redirect("/Error/NotFound"); } else { context.HttpContext.Response.Redirect("/Error/ServerError"); } return Task.CompletedTask; });
やっていることは単純なので特に説明しませんが、UseStatusCodePages
を使って目的を果たすことが出来ました。拡張メソッドを用意して、もうちょっとスマートに書けるようにも出来そうです。
実行すると、ちゃんと指定したページへリダイレクトされます。
この辺りを調べているときに IApplicationBuilder
が結構面白いことに気が付いたので、もうちょっと深堀してみようかと思います。