mvc3 ValidationSummary exclude property errors IValidatableObject

mb666 picture mb666 · Jun 22, 2011 · Viewed 8.4k times · Source

My model ( class A ) has a property ( called b ) of type B with IValidatableObject implemented.

View has got @Html.ValidationSummary(true)

In the validation summary I want to exclude errors related to properties. In class B IValidatableObject implementation is returning ValidationResult with no memberNames

But class B valiadtion errors from IValidatableObject are not displayed since class B is a property on class A

How to display class B non-property validation errors?

Answer

Manas picture Manas · May 6, 2012

I think this is pretty much straight forward, Let me explain with an example. First let me create the problem you are facing, then i will explain how to solve.

1) Declare My models.

public class ClassA
{
    [Required]
    public string Name { get; set; }
    public ClassB CBProp { get; set; }
}

public class ClassB:IValidatableObject
{
    [Required]
    public string MyProperty { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!string.IsNullOrWhiteSpace(MyProperty) && MyProperty.Length > 10)
            yield return new ValidationResult("MaxLength reached");
    }
}

2) Declare simple actions.

public class HomeController : Controller
{       
    [HttpGet]
    public ActionResult Test()
    {
        ClassA ca = new ClassA();
        return View(ca);
    }

    [HttpPost]
    public ActionResult Test(ClassA ca)
    {            
        return View(ca);
    }
}

3) Let me create a simple view and an editor template for ClassB.

Test View:

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>ClassA</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
            @Html.EditorFor(m => m.CBProp, "TestB")    
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

EditorTemplate

<div class="editor-label">
        @Html.LabelFor(model => model.MyProperty)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.MyProperty)
        @Html.ValidationMessageFor(model => model.MyProperty)
    </div>

4) Now the view will look like,

enter image description here

5) Now if we will click on Submit. with out entering any data. It will show property validation error as expected.

enter image description here

6) Now if we will enter a string with length > 10 in MyProperty, it should show the error message "MaxLength reached", But the error will not be displayed :) :)

enter image description here

Reason for this

So, If we see the code for the view, we can find the line

 @Html.ValidationSummary(true)  /// true, will excludePropertyErrors

Since, CBProp is a property in ClassA, ValidationSummary(true) will exclude any error in CBProp. So you will not find the error message being displayed. How ever there are several options available for this.

Options

1) Set @Html.ValidationSummary()

This will display the error message, But it will also display any other error message(which is redundant),like,

enter image description here

2) Set @Html.ValidationSummary(true) in the Editor Template. But it will show the error message like,

enter image description here

3) In Validate method of ClassB, specify property name along with error message in ValidationResult.Now it will be treated as a validation error for the property and will be displayed by @Html.ValidationMessageFor(model => model.MyProperty) in Editor Template.

Code

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!string.IsNullOrWhiteSpace(MyProperty) && MyProperty.Length > 10)
            yield return new ValidationResult("MaxLength reached", new List<string> { "MyProperty" });
    }

Error looks like

enter image description here

I think its now clear why the error message was not displayed, and what are the options available. Its up to you to decide the approach best suitable for you.

Cheers