27

I have something like this:

    [DisplayName("First Name")]
    [Required(ErrorMessage="{0} is required.")]
    [StringLength(50, MinimumLength = 10, ErrorMessage="{0}'s length should be between {2} and {1}.")]
    public string Name { get; set; }

I want to have the following output:

  • First Name is required.
  • First Name's length should be between 10 and 50.

It is working when using ASP.NET MVC2 Error Summary, but when I try to validate it manually, like this:

        ValidationContext context = new ValidationContext(myModel, null, null);
        List<ValidationResult> results = new List<ValidationResult>();
        bool valid = Validator.TryValidateObject(myModel, context, results, true);

The results are:

  • Name is required.
  • Name's length should be between 10 and 50.

What's wrong? Thanks.

goenning
  • 6,514
  • 1
  • 35
  • 42
  • I appear to have the same issue as the OP. In the main, using either [DisplayName] or [Display] on the property works correctly (replace {0} in the required attribute's error message with the display name), however I have discovered that the model errors output by server side validation can be incorrect (replace {0} with the Property name) - even though unobtrusive validation gives the correct value for the same property. (To see this I had to turn off javascript). I haven't yet been able to get to the bottom of this - observed with MVC 5.2.3 – Stuart Moore Oct 11 '17 at 12:01
  • Please can you tell what is the value of {0}? How do you define it? – anhtv13 Feb 07 '22 at 11:23

2 Answers2

48

Instead of (or perhaps in conjunction with) using the [DisplayName] attribute, use the [Display] attribute in System.ComponentModel.DataAnnotations. Populate its Name property.

With that, you can use built-in validation attributes or custom attributes with ValidationContext's DisplayName.

e.g.,

[Display(Name="First Name")] // <-- Here
[Required(ErrorMessage="{0} is required.")]
[StringLength(50, MinimumLength = 10, ErrorMessage="{0}'s length should be between {2} and {1}.")]
public string Name { get; set; }
Sorensen
  • 833
  • 1
  • 9
  • 13
  • Excellent... you saved my day. Where did you get this information please? – developer Oct 27 '17 at 08:11
  • 2
    Sorry, I have no recollection. [Source amnesia](https://en.wikipedia.org/wiki/Source_amnesia) strikes again. I can nevertheless say with great confidence that I didn't read it from MSDN documentation. – Sorensen Oct 27 '17 at 13:29
13

Well, I think I did it.

I had to create another attribute like this:

public class RequiredAttribute : System.ComponentModel.DataAnnotations.RequiredAttribute
{
    private String displayName;

    public RequiredAttribute()
    {
        this.ErrorMessage = "{0} is required";
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var attributes = validationContext.ObjectType.GetProperty(validationContext.MemberName).GetCustomAttributes(typeof(DisplayNameAttribute), true);
        if (attributes != null)
            this.displayName = (attributes[0] as DisplayNameAttribute).DisplayName;
        else
            this.displayName = validationContext.DisplayName;

        return base.IsValid(value, validationContext);
    }

    public override string FormatErrorMessage(string name)
    {
        return string.Format(this.ErrorMessageString, displayName);
    } 
}

And my model is:

    [DisplayName("Full name")]
    [Required]
    public string Name { get; set; }

Thankfully this DataAnnotation is extensible.

goenning
  • 6,514
  • 1
  • 35
  • 42
  • 1
    This does change the behavior of how the required tags are rendered. I will try to follow up with a solution that doesn't impact how entity framework does client side validation when I have more time to verify it meets the initial need of this question. – Jacob Brewer Mar 07 '13 at 14:42