検証属性のエラーメッセージを一元管理する

元々ある検証属性のエラーメッセージを一元管理する場合

検証属性に対応するAttributeAdapterを継承し、エラーメッセージのリソースを指定します。

using Resources;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace Sample.CustomAttributeAdapter
{
    public class CustomStringLengthAttributeAdapter : StringLengthAttributeAdapter
    {
        public CustomStringLengthAttributeAdapter(ModelMetadata metadata, ControllerContext context, StringLengthAttribute attribute)
        : base(metadata, context, attribute)
    {
            // 作成したリソースファイルを指定
            attribute.ErrorMessageResourceType = typeof(Messages);
            // リソースファイルに記述した名前を指定
            attribute.ErrorMessageResourceName = "PropertyValueStringLength";
        }
    }
}

Global.asaxのapplication_Startでリソースファイルを指定し、作成したアダプターを登録します。

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

namespace Sample
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            // リソース名の設定
            DefaultModelBinder.ResourceClassKey = "Messages";
            // アダプターの設定
            DataAnnotationsModelValidatorProvider.RegisterAdapter(
                typeof(StringLengthAttribute), typeof(CustomStringLengthAttributeAdapter));
        }
    }
}

自作した検証属性のエラーメッセージを一元管理する場合

例えば正しい日付形式かを検証する属性を自作したとします。

using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;

namespace Sample.CustomValidationAttribute
{
    /// <summary>
    /// 入力値が「yyyy/MM/dd」形式であるかを検証します。
    /// </summary>
    public class DateAttribute : ValidationAttribute
    {
        public override bool IsValid(object value)
        {
            if (value != null)
            {
                return Regex.IsMatch(value.ToString(), @"^(\d{4})/(0[1-9]|1[0-2])/(0[1-9]|[12][0-9]|3[01])$");
            }
            return false;
        }
    }
}

この場合、DataAnnotationsModelValidatorを継承し、エラーメッセージのリソースを指定します。
自作の場合は、ErrorMessageをnullにしてください。

using Resources;
using System.Web.Mvc;
using Sample.CustomValidationAttribute;

namespace Sample.CustomAttributeAdapter
{
public class CustomDateAttributeAdapter : DataAnnotationsModelValidator<DateAttribute>
    {
        public CustomDateAttributeAdapter(ModelMetadata metadata, ControllerContext context, DateAttribute attribute)
        : base(metadata, context, attribute)
    {
            attribute.ErrorMessageResourceType = typeof(Messages);
            attribute.ErrorMessageResourceName = "PropertyValueDate";
            attribute.ErrorMessage = null;
        }
    }
}

Global.asaxのapplication_Startでリソースファイルを指定し、作成したアダプターを登録します。

using Sample.CustomValidationAttribute;
using Sample.CustomAttributeAdapter;
using System.Web;
using System.Web.Mvc;

namespace Sample
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            // リソース名の設定
            DefaultModelBinder.ResourceClassKey = "Messages";
            // アダプターの設定
            DataAnnotationsModelValidatorProvider.RegisterAdapter(
                typeof(DateAttribute), typeof(CustomDateAttributeAdapter));
        }
    }
}

あとがき

毎度アダプターをGlobal.asaxに書くのもあれなのでConfigを作った方がいいかもしれません。

using Sample.CustomValidationAttribute;
using Sample.CustomAttributeAdapter;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace Sample
{
    public class AttributeAdapterConfig
    {
        public static void RegisterAttributeAdapters()
        {
            // リソース名の設定
            DefaultModelBinder.ResourceClassKey = "Messages";
            // アダプターの設定
            DataAnnotationsModelValidatorProvider.RegisterAdapter(
                typeof(StringLengthAttribute), typeof(CustomStringLengthAttributeAdapter));
            DataAnnotationsModelValidatorProvider.RegisterAdapter(
                typeof(DateAttribute), typeof(CustomDateAttributeAdapter));
        }
    }
}
using System.Web;
using System.Web.Mvc;

namespace Sample
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AttributeAdapterConfig.RegisterAttributeAdapters();
        }
    }
}