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

问题描述 投票:3回答:5

我正在使用[在我的表单上显示错误

<%= 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.
asp.net-mvc data-annotations
5个回答
-1
投票

不。反射用于获取所有DataAnnotation,并且它们始终以调用typeof(MagicSocks).GetTYpe().GetProperties()时属性出现的顺序出现。对于您的情况,我很确定派生类属性将始终出现在基本类型属性之前。

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


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

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 

    }

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
投票

我也遇到了同样的问题,创建新的视图模型是不可行的-同样,如果您具有自定义模型绑定程序,无论如何它们都将出现在验证摘要的末尾。我在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(processedKey) && !result.ContainsKey(processedKey))
            {
                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)
© www.soinside.com 2019 - 2024. All rights reserved.