如何指定Html.ValidationSummary中数据注释错误的顺序

3
我正在使用以下方式在表单上显示错误:

<%= 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个回答

3

我为此编写了一个扩展程序:

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" });

有关扩展方法的信息,请参见http://msdn.microsoft.com/en-us/library/bb383977.aspx。 - empty

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 

    }

谢谢,但我想看看是否有人提出了更优雅的解决方案,带有某种排序方式,而不仅仅依赖字母顺序。 - David

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());

0

不对。反射用于获取所有的DataAnnotations,它们总是按照通过调用typeof(MagicSocks).GetTYpe().GetProperties()来获得属性的顺序出现。在您的情况下,我很确定派生类属性将始终出现在基础类型属性之前。

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


一个人应该在哪里编写一个帮助程序来确定顺序?我在System.ComponentModel中找到的唯一东西是PropertyChangedEventManager类,但我不认为那是正确的方法。 - David Fox
当我在没有父级的编辑模型上运行此示例代码时,我会得到一个 PropertyInfo 数组,其中包含类似 System.String Name 的项,但没有公共方法。 - empty

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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接