Setting a default ErrorMessage for a custom ASP.NET MVC ValidationAttribute

I've created a custom ASP.NET MVC ValidationAttribute and I'm trying to set my own default error message on it upon instantiation by passing a string to the base constructor:

public class BusinessLogicRegex : ValidationAttribute, IClientValidatable
{
    private const string _defaultErrorMessage = "Invalid Password. {0}";
    private string _description;
    //Other private members
    ...

    public BusinessLogicRegex(string getMember, Type getMemberType, string descriptionMember, Type descriptionMemberType)
        : base(_defaultErrorMessage)
    {
        //Omitted the guts of initializing validation for brevity
        ...
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(ErrorMessage, _description);
    }
}

But when FormatErrorMessage is called, ErrorMessage is null. Why doesn't this base(_defaultErrorMessage) set the ErrorMessage property and how should I set it while still giving the user of this attribute the ability to override it?

Edit - 2nd, cleaner Example:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class TestValidator : ValidationAttribute
{
    public TestValidator()
        : base("Test Error on {0}")
    {
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(ErrorMessage, name);
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }
}

Here again, FormatErrorMessage throws a null reference exception because ErrorMessage is null. However ErrorMessageString == "Test Error on {0}". So my mistake seems to be in thinking that calling base("Test Error on {0}") sets the ErrorMessage property. I don't understand this at all. Here how the base constructor describes its errorMessage parameter:

The error message to associate with a validation control

Here is what MSDN says about the ErrorMessageString property:

The error message string is obtained by evaluating the ErrorMessage property or by evaluating the ErrorMessageResourceType and ErrorMessageResourceName properties. The two cases are mutually exclusive. The second case is used if you want to display a localized error message.

Yet inside of FormatErrorMessage at runtime, ErrorMessage , ErrorMessageResourceType and ErrorMessageResourceName are all null. So that description makes it sound like ErrorMessageString should also be null to me. This leaves me very confused about the usage and interaction between all of these properties and the constructor.


So I looked at the source code and I see why it's confusing. The ValidationAttribute class maintains a private _defaultErrorMessage field of its own. When I call base(errorMessage) it forwards my string as a lambda to the constructor that accepts a Func<string> errorMessageAccessor and sets that to a private _errorMessageResourceAccessor field. The ErrorMessageString getter first calls a method named SetupResourceAccessor where it determines whether to use

The ErrorMessage property is supported by a private _errorMessage field that appears to only be set by the ErrorMessage property setter. If _errorMessageResourceAccessor is null (which it is not in my case because I set it in the base constructor), this method will decide whether to set _errorMessageResourceAccessor to the default error message, a localized resource message, or the ErrorMessage property. However, if it is not null, it will leave _errorMessageResourceAccessor set to its current value. This is the case I am hitting. Lastly, the ErrorMessage property is supported by an _errorMessage field which appears to only get set by the ErrorMessage setter. The getter will return the default error message if ErrorMessage has not be explicitly set. Once the setter is called, it clears _errorMessageResourceAccessor .

So to try to summarize, calling ErrorMessage will give you the explicitly set error message or the default error message (which I actually don't know where it gets set. Maybe by an inheriting class?). Calling ErrorMessageString will give you a message in what looks to be the following order of presedence:

  • Default error message if nothing else is set
  • Constructor errorMessage string
  • Localized value from ErrorMessageResourceName if it and ErrorMessageResourceType are set
  • The explicitly set ErrorMessage
  • 链接地址: http://www.djcxy.com/p/56652.html

    上一篇: 如何从ASP.NET Web服务实现自定义JSON序列化?

    下一篇: 为自定义ASP.NET MVC ValidationAttribute设置默认的ErrorMessage