自定义验证摘要和错误的格式

时间:2017-10-17 23:17:32

标签: c# asp.net .net asp.net-core .net-core

问题

摘要

对于验证摘要,您通常会遇到以下情况:

<div asp-validation-summary="ModelOnly" class="..."></div>

,如果有一个空字符串的错误,因为字段/属性将显示在<ul>列表中的该div内。

如果我想使用具有特定div属性的class s序列来显示它们,该怎么办?或任何其他自定义格式?

字段验证

对于字段验证,您通常会这样做:

<div class="form-group">
    <label asp-for="OldPassword"></label>
    <input asp-for="OldPassword" class="form-control" />
    <span asp-validation-for="OldPassword" class="text-danger"></span>
</div>

并将错误作为文本插入span元素中。

我正在使用一个模板,该模板需要将has-errors类应用于form-group div元素,以防出现错误,因为它需要设置标签和输入的样式。

它还要求spandiv(由于某些未知原因),令人惊讶的是,将span更改为div会阻止div插入文本错误;更不用说将span包裹在div内会产生div应用了适当间距的问题,所以即使没有错误,div也显示出令人讨厌的空间。

问题(tl; dr)

处理自定义表单验证格式(尝试干,因为我的应用程序有很多表单)以及上面显示的自定义规则最常用的方法是什么?

2 个答案:

答案 0 :(得分:8)

以下是一些扩展点,您可以考虑为验证摘要和字段验证错误提供自定义呈现:

  • 自定义现有验证标记帮助程序(注册新IHtmlGenerator
  • 创建新的验证代码帮助程序(注册新Tag Helpers

自定义现有验证标记助手

asp-validation-summaryasp-validation-for代码帮助程序使用GenerateValidationSummary服务的注册实现的GenerateValidationMessageIHtmlGenerator方法,默认情况下为DefaultHtmlGenerator

您可以提供导出DefaultHtmlGenerator的自定义实现并覆盖这些方法,然后在启动时注册该服务。这样,这些标记帮助程序将使用您的自定义实现。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddTransient<IHtmlGenerator, MyHtmlGenerator>();
}

以下是source code of DefaultHtmlGenerator的链接,可帮助您自定义实施。

示例 - 创建新的实现IHtmlGenerator

这是一个简单的示例,用于显示所需的命名空间和方法,以及可以进入自定义实现的内容。在您提供自定义实施后,请不要忘记在ConfigureServices中注册,就像我上面所做的那样。

using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
using Microsoft.Extensions.Options;
using System.Text.Encodings.Web;

namespace ValidationSampleWebApplication
{
    public class MyHtmlGenerator : DefaultHtmlGenerator
    {
        public MyHtmlGenerator(IAntiforgery antiforgery, IOptions<MvcViewOptions> optionsAccessor, IModelMetadataProvider metadataProvider, IUrlHelperFactory urlHelperFactory, HtmlEncoder htmlEncoder, ValidationHtmlAttributeProvider validationAttributeProvider) 
            : base(antiforgery, optionsAccessor, metadataProvider, urlHelperFactory, htmlEncoder, validationAttributeProvider)
        {
        }
        public override TagBuilder GenerateValidationMessage(ViewContext viewContext, ModelExplorer modelExplorer, string expression, string message, string tag, object htmlAttributes)
        {
            return base.GenerateValidationMessage(viewContext, modelExplorer, expression, message, tag, htmlAttributes);
        }
        public override TagBuilder GenerateValidationSummary(ViewContext viewContext, bool excludePropertyErrors, string message, string headerTag, object htmlAttributes)
        {
            return base.GenerateValidationSummary(viewContext, excludePropertyErrors, message, headerTag, htmlAttributes);
        }
    }
}

创建新的验证标记助手

你也可以author your custom tag helpers。为此,它足以从TagHelper派生并覆盖Process方法。

然后,您只需在视图中注册已创建的标记助手,或在_ViewImports.cshtml

中全局注册
@using ValidationSampleWebApplication
@using ValidationSampleWebApplication.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, ValidationSampleWebApplication

同样,在创建自定义标记帮助程序以进行验证时,您可以考虑:

  • 从头开始创建验证标记助手
  • 从现有的代码助手类驱动

示例 - 将hasError类添加到表单组div

在此示例中,我创建了一个asp-myvalidation-for,可以div这样的方式应用<div class="form-group" asp-myvalidation-for="LastName">元素,并将hasError类添加到{{1}如果指定的字段有验证错误。不要忘记在div注册它,就像我上面所做的那样。

_ViewImports.cshtml

示例 - 将using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Mvc.TagHelpers; using Microsoft.AspNetCore.Mvc.ModelBinding; namespace ValidationSampleWebApplication { [HtmlTargetElement("div", Attributes = MyValidationForAttributeName)] public class MyValidationTagHelper : TagHelper { private const string MyValidationForAttributeName = "asp-myvalidation-for"; [HtmlAttributeNotBound] [ViewContext] public ViewContext ViewContext { get; set; } [HtmlAttributeName(MyValidationForAttributeName)] public ModelExpression For { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { base.Process(context, output); ModelStateEntry entry; ViewContext.ViewData.ModelState.TryGetValue(For.Name, out entry); if (entry != null && entry.Errors.Count > 0) { var builder = new TagBuilder("div"); builder.AddCssClass("hasError"); output.MergeAttributes(builder); } } } } 类添加到表单组div

在以下示例中,我已向标准field-validation-error代码帮助程序添加了div支持。现有的标记助手只支持div元素。在此,我已向asp-validation-for代码帮助程序添加了div支持,如果出现错误,则会添加asp-validation-for,否则,field-validation-error将会{ {1}}课程。

标签的默认行为是,如果标签包含内容,它不会对标签内容进行任何更改。因此,将标记帮助器添加到空div将向span添加验证错误,但对于具有某些内容的div,它只是更改div的类。不要忘记在field-validation-valid注册它,就像我上面所做的那样。

span

答案 1 :(得分:0)

使用自定义标记助手我提出了以下解决方案:

[HtmlTargetElement("ul", Attributes = AttributeName)]
public class ValidationSummaryLiItemsTagHelper : TagHelper
{
    private const string AttributeName = "model-validation-summary-list";

    [HtmlAttributeNotBound]
    [ViewContext]
    public ViewContext ViewContext { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        var errors = ViewContext.ModelState.Where(x => x.Key == "").SelectMany(x => x.Value.Errors).ToList();
        foreach (var error in errors)
        {
            output.Content.AppendFormat("<li>{0}</li>", error.ErrorMessage);
        }

        if (errors.Any() == false)
            output.SuppressOutput();
    }
}

后来我可以这样使用它:

<ul class="some-css-class" id="some-id-name" model-validation-summary-list></ul>

然后,例如,我可以使用bootstrap类直接自定义ul容器或添加任何html属性。