はじめに
ASP.NET (Core)をはじめとする Webアプリでは、URLのパスにパラメータを含めるケースがよくある。
例えば、商品の詳細を表示するページにて、URLに https://exsampl.com/product/123456
のように商品を特定するキーを含めたり、カレンダーを表示するようなページでは https://exsampl.com/calendar/2022-09
のように日付をURLに含めることもあるだろう。
そして、ASP.NET (Core) では、こうした URLのパスに含めるパラメータのことをルート・パラメータと呼び、コントローラーのアクション(メソッド)で引数として指定されたパラメータを受け取れる。
■ ルートの定義(Startup.cs)
endpoints.MapControllerRoute(
name: "product",
pattern: "product/{productId}", new
{
controller = "Product",
Action = "Index"
});
■ コントローラ
public class ProductController : Controller
[HttpGet]
public IActionResult Index(string productId)
{
System.Console.WriteLine("productId=" + productId);
}
}
ルート・パラメータに制約(入力チェック)をつける
さて、ここからが本題である。
ASP.NET (Core) のルート・パラメータは、URLのパスに含まれるパラメーターを、アクション(メソッド)の引数として容易に受け取れるが、ユーザーが自由に変更可能な URLをパラメータに使用する場合は、事前にパラメータの検証を行う必要がある。
1、2箇所程度しかルート・パラメータを使用しなのであれば、コントローラーのアクション(メソッド)内で入力検証を行ってもよいだろう。しかし、使用箇所が増えてくるとコードが煩雑になる。
そこで、IRouteConstraint
の出番である。
IRouteConstraint
は、ルート・パラメータに制約を定義するインタフェースで、条件に一致しないパラメータは、MapControllerRoute
で指定したルーティングのルールにマッチしないため、不正なパラメータがコントローラーのアクション(メソッド)に流れるのを事前に防ぐことができる。
日付チェックする制約を作ってみよう
IRouteConstraint
インタフェースの役割が分かったところで、実際にルート・パラメータが日付であるかチェックする制約を作ってみよう。
DateRouteConstraint
という名前で新たにファイルを作り、IRouteConstraint
インタフェースを実装する。
using System;
using System.Globalization;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Http;
public class DateRouteConstraint : IRouteConstraint
{
public bool Match(
HttpContext httpContext,
IRouter route,
string routeKey,
RouteValueDictionary values,
RouteDirection routeDirection)
{
//ここでルート・パラメータの検証を行う
}
}
次に、ルート・パラメータの値を検証する Match
メソッドの中身を実装する。
今回は、ルート・パラメータの値が yyyy-MM-dd
形式の文字列であれば true
、それ以外の文字であれば false
を返す処理にする。(言うまでもないが false
を返すと制約条件NGとなる)
public bool Match(
HttpContext httpContext,
IRouter route,
string routeKey,
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (values.TryGetValue(routeKey, out var routeValue))
{
var parameterValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
//パラメータが yyyy-MM-dd 形式の日付の場合 true(制約条件とマッチ)
return DateTime.TryParseExact(parameterValueString,
"yyyy-MM-dd" ,
null,
System.Globalization.DateTimeStyles.None,
out _);
}
return false;
}
制約を「ConstraintMap」に追加する
ASP.NET MVC (Core)であれば、Startup.cs
の ConfigureServices
メソッドで、先ほど作った DateRouteConstraint
クラスを制約リストに追加する。今回は date
という名前で制約を追加した。
public void ConfigureServices(IServiceCollection services)
{
services.Configure<RouteOptions>(routeOptions =>
{
routeOptions.ConstraintMap.Add("date", typeof(DateRouteConstraint));
});
}
ルーティングで制約を設定する
次に、ルーティングで制約を設定する。
今回は、https://exsample.com/calendar/2022-12-31
のような URLを想定し、この URLの日付部分のルーティング・パラメータに、上で作成した制約を設定する。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "calendar",
pattern: "calendar/{dataValue:date}", new
{
controller = "Calendar",
Action = "Index"
});
});
}
ポイントは {dataValue:date}
となっている部分である。このようにルート・パラメータ名の後ろに :制約名
を付けることにより、URLのパターンマッチの際に制約のチェックが行われ、チェックNG(結果が false)の場合、コントローラーのアクションは実行されずに 404 などのエラーページが表示される。
まとめ
ASP.NET (Core)で、ルーティング・パラメータに制約を付ける方法を紹介しました。
煩雑になりがちなパラメータのチェック処理を、コントローラー側のコードから排除できる IRouteConstraint
による制約を積極的に採用しましょう。
0 件のコメント:
コメントを投稿