web-dev-qa-db-ja.com

ASP.NET MVC3の控えめな検証でAllowEmptyString = trueのRequiredAttribute

ビューモデルに[Required(AllowEmptyStrings = true)]宣言がある場合、検証は常に空の入力でトリガーされます。私はそれが起こる理由を説明する 記事 を見つけました。利用可能な修正があるかどうか知っていますか?そうでない場合、どのように処理しますか?

21
UserControl

注:Webシナリオの外部でもビューモデルを使用しているため、AllowEmptyStrings = trueであると想定しています。それ以外の場合は、Webシナリオで空の文字列を許可するRequired属性を持つことにはあまり意味がないようです。

これを処理するには、次の3つの手順があります。

  1. その検証パラメーターを追加するカスタム属性アダプターを作成します
  2. アダプターをアダプター工場として登録する
  3. JQuery検証関数をオーバーライドして、その属性が存在するときに空の文字列を許可します

ステップ1:カスタム属性アダプター

このロジックを追加するためにRequiredAttributeAdapterを変更しました。

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace CustomAttributes
{
    /// <summary>Provides an adapter for the <see cref="T:System.Runtime.CompilerServices.RequiredAttributeAttribute" /> attribute.</summary>
    public class RequiredAttributeAdapter : DataAnnotationsModelValidator<RequiredAttribute>
    {
        /// <summary>Initializes a new instance of the <see cref="T:System.Runtime.CompilerServices.RequiredAttributeAttribute" /> class.</summary>
        /// <param name="metadata">The model metadata.</param>
        /// <param name="context">The controller context.</param>
        /// <param name="attribute">The required attribute.</param>
        public RequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredAttribute attribute)
            : base(metadata, context, attribute)
        {
        }
        /// <summary>Gets a list of required-value client validation rules.</summary>
        /// <returns>A list of required-value client validation rules.</returns>
        public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
        {
            var rule = new ModelClientValidationRequiredRule(base.ErrorMessage);
            if (base.Attribute.AllowEmptyStrings)
            {
                //setting "true" rather than bool true which is serialized as "True"
                rule.ValidationParameters["allowempty"] = "true";
            }

            return new ModelClientValidationRequiredRule[] { rule };
        }
    }
}

ステップ2.これをglobal.asax/Application_Start()に登録します

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(typeof(RequiredAttribute),
          (metadata, controllerContext, attribute) => new CustomAttributes.RequiredAttributeAdapter(metadata,
            controllerContext, (RequiredAttribute)attribute)); 

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }

ステップ3. jQueryの「必須」検証関数をオーバーライドします

これは、jQuery.validator.addMethod()呼び出しを使用して実行され、カスタムロジックを追加してから、元の関数を呼び出します。このアプローチの詳細については、 こちら をご覧ください。これをサイト全体で使用している場合は、おそらく_Layout.cshtmlから参照されているスクリプトファイルで使用します。テストするページにドロップできるサンプルスクリプトブロックは次のとおりです。

<script>
jQuery.validator.methods.oldRequired = jQuery.validator.methods.required;

jQuery.validator.addMethod("required", function (value, element, param) {
    if ($(element).attr('data-val-required-allowempty') == 'true') {
        return true;
    }
    return jQuery.validator.methods.oldRequired.call(this, value, element, param);
},
jQuery.validator.messages.required // use default message
);
</script>
22
Jon Galloway

'Required'属性で値を装飾するのではなく、以下を使用します。私はそれがこの問題の最も簡単な解決策であると思います。

[DisplayFormat(ConvertEmptyStringToNull = false)]

15
Rick Arthur