しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET MVC で指定した値が入力されているか検証する属性を作ってみた

よく会員登録などのフォームにある、会員規約に同意しますというチェックボックスってありますよね。

f:id:shiba-yan:20130528094017p:plain

ASP.NET MVC でチェックされていない時にエラーを表示する場合、Required 属性を使えば対応出来そうだと考える人は多いと思います。

public class FormModel
{
    // チェックされていない時にエラーになることを期待
    [Required(ErrorMessage = "会員規約に同意してください")]
    public bool Agree { get; set; }
}

しかし、Required 属性では期待通りに動作しません。

理由は ASP.NET MVC の CheckBoxFor メソッドで作成したチェックボックスは、チェックされていない場合には false を投げるようになっていて、Required 属性は値が存在しない場合にのみエラーを出すからです。

ということで、現状では IValidatableObject を実装して、Validate メソッドで false かどうかをチェックする必要がありますが、データアノテーションと IValidatableObject の組み合わせは多少問題がある*1ので、指定された値が入力されているか検証する属性を作りました。*2

public class RequiredValueAttribute : ValidationAttribute
{
    public RequiredValueAttribute(object requiredValue)
    {
        if (requiredValue == null)
        {
            throw new ArgumentNullException("requiredValue");
        }

        _requiredValue = requiredValue;
    }

    private readonly object _requiredValue;

    public override bool IsValid(object value)
    {
        if (value.GetType() != _requiredValue.GetType())
        {
            return false;
        }

        if (!requiredValue.Equals(value))
        {
            return false;
        }

        return true;
    }
}

作成した RequiredValue 属性はコンストラクタで指定された値と、フォームからの値が型を含めて同じものか検証するようになっています。

なので、先程のケースでは以下のように指定すれば解決できますね。

public class FormModel
{
    // チェックされていない時にエラーになることを期待
    [RequiredValue(true, ErrorMessage = "会員規約に同意してください")]
    public bool Agree { get; set; }
}

これでチェックを入れずにフォームを送信した場合にはエラーが出るようになりました。

f:id:shiba-yan:20130528094218p:plain

今回はチェックボックスで実装しましたが、ラジオボタンやドロップダウンリストにも応用出来そうです。

*1:データアノテーションの段階でエラーになると Validate メソッドは呼ばれない

*2:null の時に例外になる問題があったので修正しました