mvc3 ValidationSummary排除属性错误IValidatableObject

如何解决mvc3 ValidationSummary排除属性错误IValidatableObject

|| 我的模型(类A)具有类型B的属性(称为b),实现了
IValidatableObject
。 查看有got1ѭ 在验证摘要中,我要排除与属性有关的错误。 在类B中,
IValidatableObject
实现返回没有成员名的
ValidationResult
但是由于类B是类A的一个属性,因此不会显示来自
IValidatableObject
的类B错误。 如何显示B类非财产验证错误?     

解决方法

        我认为这很简单,让我举例说明。 首先让我提出您面临的问题,然后我将说明如何解决。 1)声明我的模型。
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)声明简单的动作。
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)让我为ClassB创建一个简单的视图和一个编辑器模板。 测试视图:
@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>
}
编辑器模板
<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)现在视图看起来像 5)现在,如果我们单击提交。无需输入任何数据。它将显示预期的属性验证错误。 6)现在,如果我们在MyProperty中输入长度大于10的字符串,它应该显示错误消息“已达到MaxLength”,但不会显示错误:) :) 原因 因此,如果我们看到该视图的代码,则可以找到该行
 @Html.ValidationSummary(true)  /// true,will excludePropertyErrors
由于CBProp是ClassA的属性,因此ѭ10将排除CBProp中的任何错误。因此,您将找不到显示的错误消息。但是,有几种方法可供选择。 选件 1)设定
@Html.ValidationSummary()
这将显示错误消息,但也会显示任何其他错误消息(这是多余的),例如, 2)在编辑器模板中设置
@Html.ValidationSummary(true)
。但是它将显示错误消息,例如 3)在ClassB的Validate方法中,在ValidationResult中指定属性名称和错误消息,现在将其视为属性的验证错误,并在编辑器模板中以
@Html.ValidationMessageFor(model => model.MyProperty)
显示。 码
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!string.IsNullOrWhiteSpace(MyProperty) && MyProperty.Length > 10)
            yield return new ValidationResult(\"MaxLength reached\",new List<string> { \"MyProperty\" });
    }
错误看起来像 我认为现在很清楚为什么未显示错误消息以及可用的选项是什么。由您决定最适合您的方法。 干杯     ,虽然验证摘要的这种行为可能不适用于您的情况,但通常必须将其视为“正确”。在模型中包含的子对象中创建错误时,会将正确的前缀添加到错误中。也就是说,如果子对象包含在属性“ 15”中,则前缀“ 15”会自动添加到所有错误中。必须为所有已创建的错误提供正确的名称-否则,
Validationsummary
和neither18ѭ都将无法正常工作-因为它们引用的是全名(包括整个前缀的名称)。这是避免歧义的唯一方法,因为您可能在两个不同的子对象中具有两个
Name
属性。 但是,通常,当子对象中生成的错误不是简单属性级别错误而是“整个对象”级别错误时,这种“正确”行为是不合适的。在这种情况下,您可能希望它们出现在常规验证摘要中。 您可以通过两种方式解决此问题: 使用特定于子对象的另一个验证摘要 错误冒泡-我经常使用错误冒泡来表示模型的子部分(未在屏幕上显示)包含错误,因此用户可以打开详细信息窗口(jQuery对话框或类似窗口)以查看错误。基本上,错误冒泡在于使用
foreach
处理ModelState中的所有错误,然后将其中的一些错误提升。提升意味着删除错误前缀的最后一部分。提出错误时,您可以保留还是不保留原始错误-保留原始错误也比较容易,并且在大多数情况下,这是正确的做法。请注意,在循环浏览所有条目时不能删除条目-必须将其放入列表中,然后在循环终止后将其删除。 推广标准可能取决于您的需求。我举个例子: 提升属性级别错误会将其转换为对象级别错误。 提升子对象级错误会将其转换为外部对象的对象级错误。这种情况应该引起您的兴趣-只需推广与包含整个对象而不是简单值的根level21ѭ的属性相关的对象级错误! 可以在您可以定义的自定义ActionFilter中执行错误处理,然后将其与几种操作方法一起使用。 以下是简单的PromoteAttribute ActionFilter的代码。它的用途是:
[Promote(\"prop1.SubProp1 Prop2\")]
public ActionResult MyMethod( ...
那就是给它传递了一个要升级到Root模型的表达式错误列表,如果它在ModelState中找到与它们匹配的错误,它将对其进行升级-显然,这只是一个简单的例子-您可以将其升级到一个级别而不是一个根,您可以使用复杂的条件来定位要推广的错误,而不是列出它们:
public class PromoteAttribute : ActionFilterAttribute
{
    string[] expressions;
    public PromoteAttribute(string toPromote)
    {
        expressions = toPromote.Split(\' \');
    }
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        ModelStateDictionary modelState=filterContext.Controller.ViewData.ModelState;
        foreach(var x in expressions)
        {
            if (modelState.ContainsKey(x))
            {
                var entry = modelState[x];
                if (entry.Errors.Count == 0) continue; 

                foreach (var error in entry.Errors) modelState.AddModelError(\"\",error.ErrorMessage);

            }
        }
    }
}
    ,        挖出MVC3的源代码并进行编辑以允许包含属性。
@Html.ValidationSummary(new [] { \"PropertyName\" })
将包含名为PropertyName的属性
@Html.ValidationSummary(new [] { \"ArrayName[]\" })
将包括属性ArrayName [0],ArrayName [1]等。
@Html.ValidationSummary(new [] { \"ArrayName[]\",\"PropertyName\" })
将包括两者。
public static MvcHtmlString ValidationSummary(this HtmlHelper htmlHelper,string[] includePropertyErrors)
{
    return ValidationSummary(htmlHelper,includePropertyErrors,null,null);
}

public static MvcHtmlString ValidationSummary(this HtmlHelper htmlHelper,string[] includePropertyErrors,string message)
{
    return ValidationSummary(htmlHelper,message,string message,IDictionary<string,object> htmlAttributes)
{
    if (htmlHelper == null)
    {
        throw new ArgumentNullException(\"htmlHelper\");
    }

    FormContext formContext = htmlHelper.ViewContext.ClientValidationEnabled ? htmlHelper.ViewContext.FormContext : null;
    if (htmlHelper.ViewData.ModelState.IsValid)
    {
        if (formContext == null)
        {  // No client side validation
            return null;
        }

        // TODO: This isn\'t really about unobtrusive; can we fix up non-unobtrusive to get rid of this,too?
        if (htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
        {  // No client-side updates
            return null;
        }
    }

    string messageSpan;
    if (!string.IsNullOrEmpty(message))
    {
        TagBuilder spanTag = new TagBuilder(\"span\");
        spanTag.SetInnerText(message);
        messageSpan = spanTag.ToString(TagRenderMode.Normal) + Environment.NewLine;
    }
    else
    {
        messageSpan = null;
    }

    StringBuilder htmlSummary = new StringBuilder();
    TagBuilder unorderedList = new TagBuilder(\"ul\");

    IEnumerable<ModelState> modelStates = from ms in htmlHelper.ViewData.ModelState
                                            where ms.Key == htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix ||
                                                includePropertyErrors.Any(property =>
                                                {
                                                    string prefixedProperty = string.IsNullOrEmpty(htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix) ? property : htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix + \".\" + property;
                                                    if (property.EndsWith(\"[]\"))
                                                    {
                                                        return prefixedProperty.Substring(0,property.Length - 2) == Regex.Replace(ms.Key,@\"\\[[^\\]]+\\]\",string.Empty);
                                                    }
                                                    else
                                                    {
                                                        return property == ms.Key;
                                                    }
                                                })
                                            select ms.Value;

    if (modelStates != null)
    {
        foreach (ModelState modelState in modelStates)
        {
            foreach (ModelError modelError in modelState.Errors)
            {
                string errorText = GetUserErrorMessageOrDefault(htmlHelper.ViewContext.HttpContext,modelError);
                if (!String.IsNullOrEmpty(errorText))
                {
                    TagBuilder listItem = new TagBuilder(\"li\");
                    listItem.SetInnerText(errorText);
                    htmlSummary.AppendLine(listItem.ToString(TagRenderMode.Normal));
                }
            }
        }
    }

    if (htmlSummary.Length == 0)
    {
        htmlSummary.AppendLine(@\"<li style=\"\"display:none\"\"></li>\");
    }

    unorderedList.InnerHtml = htmlSummary.ToString();

    TagBuilder divBuilder = new TagBuilder(\"div\");
    divBuilder.MergeAttributes(htmlAttributes);
    divBuilder.AddCssClass((htmlHelper.ViewData.ModelState.IsValid) ? HtmlHelper.ValidationSummaryValidCssClassName : HtmlHelper.ValidationSummaryCssClassName);
    divBuilder.InnerHtml = messageSpan + unorderedList.ToString(TagRenderMode.Normal);

    if (formContext != null)
    {
        if (!htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
        {
            // client val summaries need an ID
            divBuilder.GenerateId(\"validationSummary\");
            formContext.ValidationSummaryId = divBuilder.Attributes[\"id\"];
            formContext.ReplaceValidationSummary = false;
        }
    }

    return new MvcHtmlString(divBuilder.ToString(TagRenderMode.Normal));
}

private static string GetUserErrorMessageOrDefault(HttpContextBase httpContext,ModelError error)
{
    return string.IsNullOrEmpty(error.ErrorMessage) ? null : error.ErrorMessage;
}
    ,让我们从我们所知道的开始: 正如描述所暗示的,如果我们有我们的模型: 模型A:
public class A
{
    public B ModelB { get; set; }
}
型号B:
public class B : IValidatableObject
{
    public string Name { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        List<ValidationResult> errors = new List<ValidationResult>();

        if (string.IsNullOrEmpty(Name)) {
            errors.Add(new ValidationResult(\"Please enter your name\"));
        }

        return errors;
    }
}
和我们的看法:
@model A

@Html.ValidationSummary(true)

@using (Html.BeginForm())
{
    @Html.EditorFor(model => model.ModelB.Name)

    <input type=\"submit\" value=\"submit\" />
}
然后编辑器将输出以下行:
<input class=\"text-box single-line\" id=\"ModelB_Name\" name=\"ModelB.Name\" type=\"text\" value=\"\" />
如果我们将后动作定义为:
[HttpPost]
public ActionResult Index(A model)
{
    if (ModelState.IsValid)
    {
        return RedirectToAction(\"NextAction\");
    }
    return View();
}
然后,当绑定到
A
模型时,
DefaultModelBinder
将查找名为
ModelB.Name
的属性,它将找到并成功绑定到该属性。 但是,由
DefaultModelBinder
针对
A
模型执行的模型验证将称为为call38ѭ模型定义的验证。该验证将返回未针对属性定义的错误消息,但是由于此验证是复杂模型的一部分,因此将使用\“ ModelB \”键将其添加到ModelState。 调用
ValidationSummary
时,它将查找空白的键(即为模型而不是属性定义的键)。由于不存在空白键,因此不会显示错误。 作为一个简单的解决方法,您可以为
B
模型定义一个
EditorTemplate
。 在包含视图的文件夹中,定义一个名为
EditorTemplates
的文件夹,并在其中创建一个与模型同名的视图(例如,本例中为
B.cshtml
)。编辑器模板的内容将定义为:
@model MvcApplication14.Models.B

@Html.EditorFor(m => m.Name)
然后,修改主视图,使
EditorFor
看起来像:
@Html.EditorFor(model => model.ModelB,\"\")
\“ \”指定我们的编辑器模板输出的任何字段都不会在该字段前加上名称。因此,输出现在将是:
<input class=\"text-box single-line\" id=\"Name\" name=\"Name\" type=\"text\" value=\"\" /> 
但是,这现在将阻止
ModelB
的绑定,因此需要在后期操作中单独进行绑定,并将其添加到我们的
A
模型中:
[HttpPost]
public ActionResult Index(A modelA,B modelB)
{
    modelA.ModelB = modelB;
    if (ModelState.IsValid)
    {
        return RedirectToAction(\"NextAction\");
    }
    return View();
}
现在,当绑定ѭ51时,验证消息将使用键“ \”写入the52ѭ。因此,这现在可以用
@ValidationMessage()
例程显示。 警告:以上解决方法假设
modelB
modelA
的字段名称不同。例如,如果
modelB
modelA
都具有
Name
字段,则
DefaultModelBinder
可能不会将字段绑定到其正确的等价物。例如,如果
A
模型还具有一个名为
Name
的字段,则必须将其写入视图:
@Html.EditorFor(model => model.Name,\"modelA.Name\")
以确保正确绑定。 希望这将使您能够使用MVC3框架中已定义的方法获得所需的结果。     ,        对于那些发现此问题的人,请看看
ViewData.TemplateInfo.HtmlFieldPrefix
(如其他答案所提到的那样)... 如果显式添加摘要级别的验证错误,通常可以(对根对象)执行此操作...
ModelState.AddModelError(\"\",\"This is a summary level error text for the model\");
当为模型属性(本身就是对象)添加类似摘要的验证错误时,您可以执行以下操作:
ModelState.AddModelError(\"b\",\"This is a \'summary\' error for the property named b\");
其中“ 66”是属性的名称,该属性本身就是属性。 为了说明,直接添加摘要级别验证错误时,您只需为对象属性指定HTML前缀即可。 可以使用
ViewData.TemplateInfo.HtmlFieldPrefix
获得。     ,        ModelState modelState =默认值(ModelState); Model.TryGetValue(this.ViewData.TemplateInfo.HtmlFieldPrefix,在modelState之外); var isExcludePropertyErrors = modelState!= null;     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-