.NET TIPS

[ASP.NET MVC]ルート・パラメータに妥当な日付が渡されているかを判定するには?[3.5、4以降、C#、VB]

山田 祥寛
2010/08/26

 「TIPS:[ASP.NET MVC]有効期限のあるルーティング規則を定義するには?」では、IRouteConstraintインターフェイス(System.Web.Routing名前空間)の実装クラスを利用して、ルートに有効期限を設ける方法について紹介した。もっとも、IRouteConstraint実装クラスの役割は、ルートそのものに対して制約を設けるばかりではない。ルート・パラメータに対する「複雑な」制約条件を定義することも可能だ。

 「複雑な」はややあいまいな言い回しであるので、もう少し具体的に見てみよう。例えば、「TIPS:[ASP.NET MVC]ルート・パラメータに制約条件を追加するには?」では、以下のようなArticleルートを定義した。

routes.MapRoute(
  "Article",
  "Article/{day}/{month}/{year}",
  ……中略 ……
  new {
    day = @"\d{1,2}",      // 日は1〜2けた
    month = @"\d{1,2}",    // 月は1〜2けた
    year = @"\d{4}"        // 年は4けた
  }
);
routes.MapRoute( _
  "Article", _
  "Article/{day}/{month}/{year}", _
  ……中略……
  New With { _
    .day = "\d{1,2}", _    ' 日は1〜2けた
    .month = "\d{1,2}", _  ' 月は1〜2けた
    .year = "\d{4}" _      ' 年は4けた
  } _
)
ルート・パラメータに制約条件を追加した例(上:Global.asax.cs、下:Global.asax.vb)
VBのコードのコメント部分は、削除しないとビルドに失敗するので、注意してほしい。このコードでは、説明を分かりやすくするために、このように記述している。

 ここでは正規表現パターンによって、{year}パラメータは数値4けたであることを、{month}/{day}パラメータは数値1〜2けたであることを、それぞれ定義している。これによって、不正なパラメータ(年月日)がArticleルートにマッチする可能性が低くなり、より精度の高いルーティングが実現できるというわけだ。

 このように正規表現による指定だけでも、それなりの制約条件を設定することはできる。しかし、厳密にはこれだけではまだ不足である。というのも、上のArticleルートでは「〜Article/35/03/2010」のようなあり得ない日付パラメータにもマッチしてしまう。当然、これは好ましい状態ではないので、制約条件であらかじめ除外しておきたいところだ。

 しかし、このように{year}、{month}、{day}と複数にまたがるパラメータの妥当性、また、数値範囲の妥当性などは、正規表現だけではチェックできない。そこで登場するのが、IRouteConstraint実装クラスなのだ。本稿では、{year}、{month}、{day}パラメータに渡された年月日が妥当な日付であるかどうかを判定する、YmdConstraint制約条件を定義する方法について見ていく。

1. 制約条件クラスを実装する

 まずは、制約条件を表すYmdConstraintクラスの定義からだ。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;

namespace MvcAppCs.Extensions {
  public class YmdConstraint : IRouteConstraint {

    // ルートが有効であるかを判定するMatchメソッド
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {

      // {year}、{month}、{day}パラメータから
      // 日付文字列「YYYY/MM/DD」を生成
      var ymd = String.Format("{0}/{1}/{2}",
        values["year"], values["month"], values["day"]);

      try {
        // 日付文字列を解析
        DateTime.Parse(ymd);
      } catch (FormatException e) {
        // 解析に失敗した場合、ルートは無効
        return false;
      }
      return true;
    }
  }
}
Public Class YmdConstraint
  Implements IRouteConstraint

  ' ルートが有効であるかを判定するMatchメソッド
  Public Function Match(ByVal httpContext As HttpContextBase, ByVal route As Route, ByVal parameterName As String, ByVal values As RouteValueDictionary, ByVal routeDirection As RouteDirection) As Boolean Implements IRouteConstraint.Match

    ' {year}、{month}、{day}パラメータから
    ' 日付文字列「YYYY/MM/DD」を生成
    Dim ymd = String.Format("{0}/{1}/{2}", _
      values("year"), values("month"), values("day"))

    Try
      ' 日付文字列を解析
      DateTime.Parse(ymd)
    Catch e As FormatException
      ' 解析に失敗した場合、ルートは無効
      Return False
    End Try
    Return True
  End Function
End Class
ルート・パラメータに渡された日付が妥当であるかをチェックする制約条件(上:YmdConstraint.cs、下:YmdConstraint.vb)

 制約条件クラスで実装しなければならないメソッドは、ルートの妥当性を判定するためのMatchメソッドだけである。Matchメソッドの中でルート・パラメータにアクセスするには、Matchメソッドの第4引数として渡されるRouteValueDictionaryオブジェクト(System.Web.Routing名前空間)にアクセスすればよい。

 ここでは、取得した{year}、{month}、{day}パラメータを基に、まずYYYY/MM/DD形式の日付文字列を組み立てる。後は、これをDateTime.Parseメソッドで解析するだけだ。Parseメソッドは不正な日付文字列が指定された場合には、FormatException例外を発生する。ここでは、Parseメソッドのこの性質を利用して、例外が発生した場合にはfalse(=ルートは無効)を返しているわけだ。

2. 制約条件付きのルートを定義する

 制約条件クラスが定義できたら、実際にArticleルートに制約条件を適用してみよう。Articleルートそのものに関する詳細は、前述の「TIPS:[ASP.NET MVC]ルート・パラメータに制約条件を追加するには?」も併せて参照していただきたい。

using MvcAppCs.Extensions;
  ……中略……
routes.MapRoute(
  "Article",                       // ルート名
  "Article/{day}/{month}/{year}",  // URIパターン
  new {
    controller = "Route",          // コントローラ名
    action = "Index",              // アクション名(*1
  },
  new {
    ymd = new YmdConstraint()
  }                                // 制約条件
);
routes.MapRoute( _
  "Article", _                       ' ルート名
  "Article/{day}/{month}/{year}", _  ' URIパターン
  New With { _
    .controller = "Route", _         ' コントローラ名
    .action = "Index", _             ' アクション名(*1
  }, _
  New With { _
    .ymd = New YmdConstraint()
  } _                                ' 制約条件
)
YmdConstraint制約条件を適用したArticleルートを定義(上:Global.asax.cs、下:Global.asax.vb)
VBのコードのコメント部分は、削除しないとビルドに失敗するので、注意してほしい。このコードでは、説明を分かりやすくするために、このように記述している。

*1 Route/Indexアクションについては、「TIPS:[ASP.NET MVC]ルート定義を追加するには?」で作成したものを使用している。内容にはとりたてて影響しないが、気になる方はそのTIPSの内容も併せて参照していただきたい。

 制約条件は、「キー名 = IRouteConstraint実装クラスのインスタンス」の匿名型として指定する。ルート側の記述については、とりたてて特筆すべき点はないだろう。

 以上を理解できたら、さっそく、

http://localhost:8080/Article/29/02/2010

のようなURLでアクセスしてみよう。2010年2月29日は存在しない日付であるので、404 Not Foundエラーが返される(=ルートが無効化されている)はずだ。同じく、

http://localhost:8080/Article/28/02/2010

のようなURL(妥当な日付)でアクセスし、Articleルートが正しく適用されることも確認してほしい。End of Article

利用可能バージョン:.NET Framework 3.5
利用可能バージョン:.NET Framework 4
カテゴリ:ASP.NET MVC 処理対象:ルーティング
使用ライブラリ:IRouteConstraintインターフェイス(System.Web.Routing名前空間)
使用ライブラリ:RouteValueDictionaryクラス(System.Web.Routing名前空間)
使用ライブラリ:FormatExceptionクラス(System)
関連TIPS:[ASP.NET MVC]有効期限のあるルーティング規則を定義するには?
関連TIPS:[ASP.NET MVC]ルート・パラメータに制約条件を追加するには?
関連TIPS:[ASP.NET MVC]ルート定義を追加するには?

この記事と関連性の高い別の.NET TIPS
[ASP.NET MVC]有効期限のあるルーティング規則を定義するには?
[ASP.NET MVC]特定のHTTPメソッドにマッチするルートを定義するには?
[ASP.NET MVC]ルート・パラメータに制約条件を追加するには?
[ASP.NET MVC]ルート定義を追加するには?
[ASP.NET MVC]特定のルートを無効化するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間