IaCoder
IaCoder

Reputation: 12770

Error messages for model validation using data annotations

Given the following classes:

using System.ComponentModel.DataAnnotations;

public class Book{
   public Contact PrimaryContact{get; set;}
   public Contact SecondaryContact{get; set;}

   [Required(ErrorMessage="Book name is required")]
   public string Name{get; set;}
}
public class Contact{
    [Required(ErrorMessage="Name is required")]
    public string Name{get; set;}
}

Is there a clean way I can give a distinct error message for each instance of Contact in Book using DataAnnotations? For example, if the name was missing from the PrimaryContact instance the error would read "primary contact name is required".

My current solution is to create a validation service that checks the model state for field errors, then remove said errors and add them back using the specific language I'd like.

Upvotes: 25

Views: 114204

Answers (4)

synthetik
synthetik

Reputation: 151

You may want to look at using the CustomValidation attribute for such properties instead of relying on the Required attribute.

CustomValidation will allow you to more granularly tailor your validation messages to the property you are validating. I've used context.DisplayName to dynamically display the name of the property being validated just for brevity, but this can be customized further based on your needs.

If even further customization is needed, you can write different CustomValidation handlers for each individual property instead of just reusing the same one as I've done in my code example.

using System.ComponentModel.DataAnnotations;

public class Book {
    [CustomValidation(typeof(Book), "ValidateContact")]
    public Contact PrimaryContact { get; set; }

    [CustomValidation(typeof(Book), "ValidateContact")]
    public Contact SecondaryContact { get; set; }

    [Required(ErrorMessage = "Book name is required")]
    public string Name { get; set; }

    public static ValidationResult ValidateContact(Contact contact, ValidationContext context) {
        ValidationResult result = null;

        if (contact == null) {
            result = new ValidationResult($"{context.DisplayName} is required.");
        } else if (string.IsNullOrWhiteSpace(contact.Name)) {
            result = new ValidationResult($"{context.DisplayName} name is required.");
        }

        return result;
    }
}

public class Contact {
    [Required(ErrorMessage = "Name is required")]
    public string Name { get; set; }
}

Upvotes: 15

Kailash Mali
Kailash Mali

Reputation: 87

The Below code in c# to format data annotations error and format in append format in single string

  public class ValidateModelAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (actionContext.ModelState.IsValid == false)
            {
                if (actionContext.ModelState.IsValid) return;
                string errors = actionContext.ModelState.SelectMany(state => state.Value.Errors).Aggregate("", (current, error) => current + (error.ErrorMessage + ". "));
            }
        }
    }

Upvotes: 2

Chris Stephens
Chris Stephens

Reputation: 2174

I'm looking for answer to this too, what I have found so far if you do something like: "{0} Contact Name is required" in the Error message it will automatically substitute the name of the variable. I figure there is a way to explicitly use this feature.

Upvotes: 0

Jab
Jab

Reputation: 13775

This is the only way I know of that, but it's far from clean. It involves using subclassing and MetaData classes to "override" the error message.

public class Book
{
    public PrimaryContact PrimaryContact { get; set; }
    public SecondaryContact SecondaryContact { get; set; }

    [Required(ErrorMessage = "Book name is required")]
    public string Name { get; set; }
}

public class Contact
{
    [Required(ErrorMessage = "Name is required")]
    public string Name { get; set; }
}

[MetadataType(typeof(PrimaryContactMD))]
public class PrimaryContact : Contact
{
    class PrimaryContactMD
    {
        [Required(ErrorMessage = "Primary Contact Name is required")]
        public string Name { get; set; }
    }
}

[MetadataType(typeof(SecondaryContactMD))]
public class SecondaryContact : Contact
{
    class SecondaryContactMD
    {
        [Required(ErrorMessage = "Secondary Contact Name is required")]
        public string Name { get; set; }
    }
}

Upvotes: 47

Related Questions