Stop Html.ValidationSummary () from reordering validation messages

In ValidationSummary, why do the messages appear in a different order than the order you added to ModelState, and how can I fix this?

+2


source to share


5 answers


asp.net mvc is open source, so you can view the code for ValidationSummary directly.

http://www.asp.net/mvc/download/

However, I'm pretty sure ModelState is a dictionary. So if ValidationSummary iterates over the keywords / values ​​in the ModelState dictionary looking for errors, the order will be random.


I have uploaded the code to work. From ValidationSummary in MVC / Html / ValidationExtensions.cs:

foreach (ModelState modelState in htmlHelper.ViewData.ModelState.Values) {
    foreach (ModelError modelError in modelState.Errors) {
        // stuff to build a string with the error
    }
}

      



So it iterates over the values ​​in the dictionary. And from MSDN:

For enumeration purposes, each element in the dictionary is treated as a KeyValuePair (TKey, TValue) structure representing a value and its key. The order in which elements are returned is undefined.

and

Order of values ​​in dictionary (TKey, TValue) .ValueCollection unspecified

Emphasis on mine.

+1


source


<ul class="validation-summary-errors">
<%

       foreach (ModelState modelState in (ViewContext.ViewData.ModelState.Values)){
        foreach (ModelError modelError in modelState.Errors) {
            // stuff to build a string with the error
                %>
                <li><%=modelError.ErrorMessage %></li>
                <%   
        }
    }
%>
</ul>

      



This might be helpful.

+2


source


I ran into this problem and for a quick fix, I recreated the validation summary as above and used a ViewBag to store the errors in the correct order, referencing an array of ordered field names. Not particularly pleasant, but the fastest thing I could think of at the time. Shaver / MVC 3.

Controller code:

    List<string> fieldOrder = new List<string>(new string[] { 
"Firstname", "Surname", "Telephone", "Mobile", "EmailAddress", "AddressLine1", "AddressLine2", "TownCity", "County" })
.Select(f => f.ToLower()).ToList();

    ViewBag.SortedErrors = ModelState
       .Select(m => new { Order = fieldOrder.IndexOf(m.Key.ToLower()), Error = m.Value})
       .OrderBy(m => m.Order)
       .SelectMany(m => m.Error.Errors.Select(e => e.ErrorMessage))
       .ToArray();

      

Then in the view:

@if (!ViewData.ModelState.IsValid)
{
    <div class="validation-summary-errors">  
    <ul>
        @foreach (string sortedError in ViewBag.SortedErrors)
        {
            <li>@sortedError</li> 
        }
    </ul>
    </div>
}

      

+2


source


ValidationSummary is as simple as above, it's just 2 loops (which you can do in 1 with LINQ SelectMany), so you can make your own partial view for this and put it in the layout in 5 minutes.

And given that ValidationSummary will not display Exceptions set in ModelState, there is a good reason for that.

If you want to have the same order as the controls in your view, you can do jQuery:

var list = {};
<% foreach (var error in ModelState)
{%>
  list['<%=error.Key%>'] = '<%=error.Value.Message%>';
<%}%>
$(*[name]).each(function(i,o){
  isError = list.indexOf(o.name) >= 0;
  if (isError)
     $(".validationSummary").append("<li>" + list[o.name] + "</li>");
});

      

Well, this code is out of my head, so it's pseudo ... but it's an idea. Basically you iterate over all elements with a name attribute and check the ModelState for and error. To make this happen, your server-side code creates a client-side error dictionary.

Better would be to write an extension, HtmlHelper, that basically does the same thing, but in a C # code file so that it doesn't mess up your view.

+1


source


In addition to the previous answers, you can use FluentValidation rather than data annotations. If, in order to avoid using ModelState

and creating the validator manually, then the object ValidationResult

will contain errors in the same order as the rules added to the constructor of the validator.

In addition, if client-side validation is enabled, the order of error messages is the same as the order of the corresponding inputs generated using HtmlHelper

(perhaps the same behavior should be for inputs generated in Data Annotations).

See here for details .

0


source







All Articles