読者です 読者をやめる 読者になる 読者になる

C# + Nancyで、FluentValidationを使ってデータチェックを行う

C# Nancy

前回、NancyでModelBindingを使ってデータを受け取ったので、次はそのデータに対してチェックをしたいと考えました。

何か良いものがないかを探してみたところ、FluentValidationを使ってデータチェックする、Nancy.Validation.FluentValidationというNuGetパッケージがありました。
NuGet Gallery | Nancy.Validation.FluentValidation

stackoverflowを見ると、Nancy v0.12以降では特に設定することなく使えそうだったので、試してみることにしました。
configuration - Configure NancyFx with Fluent Validation - Stack Overflow

 

環境

 

インストール

NuGetよりNancy.Validation.FluentValidationをインストールします。

上記のプロジェクトテンプレートには3つのプロジェクトが含まれますが、Nancy.Validation.FluentValidationはすべてのプロジェクトに必要です。

 

Modelを書く

NancyにModelBindingするModelを書きます。

public class HomeModel
{
    public string Text { get; set; }
    public string TextArea { get; set; }
    public string Tel { get; set; }
    public string Url { get; set; }
    public string Email { get; set; }
    public DateTime DateFrom { get; set; }
    public DateTime DateTo { get; set; }
    public List<string> ErrorMessages { get; set; }
}

一番最後のListは、エラーメッセージを表示するために使います。

 

Validatorを書く

まずは、

public class HomeValidator : FluentValidation.AbstractValidator<HomeModel>

のように、FluentValidation.AbstractValidatorを継承して、Validation対象のModelの型を指定します。

次にコンストラクタにて、Validation内容を記述します。

public HomeValidator()
{
    // Emptyでないか
    RuleFor(model => model.Text).NotEmpty();

    // Emptyでないか & 自作のメッセージを表示
    RuleFor(model => model.Tel).NotEmpty().WithMessage("Required!!");

    // 入力必須、かつ、文字長が1-10文字
    RuleFor(model => model.TextArea)
        .NotEmpty()
        .Length(1, 10);

    // 正規表現にマッチしているか
    RuleFor(model => model.Url).Matches(@"^http://");

    // メールアドレスの形式にマッチしているか
    RuleFor(model => model.Email).EmailAddress();

    // 日付の大小関係は正しいか
    RuleFor(model => model.DateFrom).GreaterThan(DateTime.Parse("2015/01/01"));

    // 日付の大小関係を確認し、独自エラーメッセージ中に、Modelのプロパティ値を参照して表示
    RuleFor(model => model.DateTo).LessThan(DateTime.Parse("2015/02/01"))
        .WithMessage("{0} is not less than '2015/2/1'", model => model.DateTo);

    // 2つの日付間の大小関係は正しいか
    RuleFor(model => model.DateFrom).LessThanOrEqualTo(model => model.DateTo);
}

 

Moduleの追加

Moduleでは、

  • this.BindAndValidate<T>()にて、ModelBindingとValidationを同時実行
  • ModelValidationResultにValidation結果が入るため、それを使ってValidationエラー時処理を実行

を以下のように実装します。

// ValidationとModelBindingを同時に実行
var model = this.BindAndValidate<HomeModel>();

if (!ModelValidationResult.IsValid)
{
    // エラーがあった場合の処理
    foreach (var error in ModelValidationResult.Errors)
    {
        var msg = error.Key + " - " + error.Value.FirstOrDefault().ErrorMessage;
        model.ErrorMessages.Add(msg);
    }
}

 
これらにより、ModelBindingと同時にエラーチェックをすることができるようになりました。

 

実行結果

f:id:thinkAmi:20150405192605p:plain

 

ソースコード

GitHubに上げました。
thinkAmi-sandbox/NancyFluentValidation-sample

 

参考

公式ドキュメント

FluentValidationの公式ドキュメントが充実していますので、参考になります。GitHubがメインのようですが、ドキュメントはまだ追いついていない部分もあるため、codeplexの方もリンクを貼っておきます。

 

その他