如何在Html.ValidationSummary中指定Data Annotation错误的顺序

时间:2010-10-12 08:19:03

标签: asp.net-mvc data-annotations

我使用

在表单上显示错误
<%= Html.ValidationSummary("Please review the errors below") %>

我的域对象继承自基类,我发现基类数据注释属性显示在列表的底部。这违反了它们在我的表单中出现的顺序。

有没有办法指定错误的显示顺序?

示例:

public class ClassA { [Required]public string AProperty; }
public class ClassB : ClassA { [Required]public string BProperty; }

我的表单(ClassB的强类型视图):

AProperty: <%= Html.TextBoxFor(m => m.AProperty) %>
BProperty: <%= Html.TextBoxFor(m => m.BProperty) %>

验证错误显示为:

The BProperty is required.
The AProperty is required.

5 个答案:

答案 0 :(得分:1)

我为此写了一个扩展名:

public static void OrderByKeys(this ModelStateDictionary modelStateDictionary, IEnumerable<string> keys)
{
    ModelStateDictionary result = new ModelStateDictionary();
    foreach (string key in keys)
    {
        if (modelStateDictionary.ContainsKey(key) && !result.ContainsKey(key))
        {
            result.Add(key, modelStateDictionary[key]);
        }
    }
    foreach (string key in modelStateDictionary.Keys)
    {
        if (!result.ContainsKey(key))
        {
            result.Add(key, modelStateDictionary[key]);
        }
    }
    modelStateDictionary.Clear();
    modelStateDictionary.Merge(result);
}

您可以使用:

ModelState.OrderByKeys(new[] { "AProperty", "BProperty" });

答案 1 :(得分:0)

我不确定我的答案是对还是错,你可以这样试试。

   public ActionResult yourAction(your params)
    { 
           if (!ModelState.IsValid)
            {
                var errs = from er in tmpErrs
                           orderby er.Key
                           select er;

                ModelState.Clear();

                foreach (var err in errs)
                {
                    ModelState.Add(err);
                }
            }
    // your code 

    }

答案 2 :(得分:0)

尝试使用此过滤器属性,该属性根据请求的表单键对模型状态进行排序。

using System.Linq;
using System.Web.Mvc;

namespace 
{
    public class OrderedModelStateAttribute : FilterAttribute, IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {
            var modelState = filterContext.Controller.ViewData.ModelState;
            var orderedModelState = new ModelStateDictionary();

            foreach (var key in filterContext.HttpContext.Request.Form.Keys.Cast<string>()
                                             .Where(
                                                 key =>
                                                 modelState.ContainsKey(key) && !orderedModelState.ContainsKey(key)))
            {
                orderedModelState.Add(key, modelState[key]);
            }

            foreach (var key in modelState.Keys.Where(key => !orderedModelState.ContainsKey(key)))
            {
                orderedModelState.Add(key, modelState[key]);
            }

            modelState.Clear();
            modelState.Merge(orderedModelState);
        }

        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
        }
    }
}

使用以下代码将过滤器添加到所有操作: filters.Add(new OrderedModelStateAttribute());

答案 3 :(得分:0)

我遇到了同样的问题,创建一个新的视图模型是不可行的-同样,如果您有自定义模型绑定程序,无论如何它们都将出现在验证摘要的末尾。我在Aphize答案上进行了扩展,而不是将属性名称列表传递给它,而可以通过表单键传递给它-这将确保顺序与它们在表单中的显示顺序相同,例如

ModelState.OrderByKeys(Request.Form.AllKeys);

这对我有用,我创建了一个属性来执行此操作。(我不得不做一些调整以处理自定义活页夹,但是这里没有做):

public class ForceValidationErrorOrderAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var allFormKeys = filterContext.HttpContext.Request.Form.AllKeys;
        var modelStateDictionary = filterContext.Controller.ViewData.ModelState;

        ModelStateDictionary result = new ModelStateDictionary();
        foreach (string key in allFormKeys)
        {
            if (modelStateDictionary.ContainsKey(key) && !result.ContainsKey(key))
            {
                result.Add(key, modelStateDictionary[key]);
            }
        }
        foreach (string key in modelStateDictionary.Keys)
        {
            if (!result.ContainsKey(key))
            {
                result.Add(key, modelStateDictionary[key]);
            }
        }
        modelStateDictionary.Clear();
        modelStateDictionary.Merge(result);
        }
    }

然后在控制器上执行操作方法:

    [ForceValidationErrorOrder]
    public ActionResult Apply(ApplicationViewModel viewModel)

答案 4 :(得分:-1)

不。反射用于获取所有DataAnnotations,它们始终按照调用typeof(MagicSocks).GetTYpe().GetProperties()时属性显示的顺序显示。在您的情况下,我非常确定派生类属性将始终出现在基类型属性之前。

您必须编写自己的帮助程序和我们自己的属性,以按您选择的顺序显示验证错误。