Tag Helper asp-validation-for 始终显示

Tag Helper asp-validation-for is always showing

我尝试使用 Asp.Net Core TagHelper,但它似乎不起作用。但是,当使用 HtmlHelpers 时,它会按预期工作。我的问题是,尽管 ModelState 有效,但它始终显示错误消息。我做错了什么或者有人可以重现这个错误吗?

<label class="control-label" asp-for="Firstname">Firstname</label>
<input type="text" class="form-control" asp-for="Firstname">
<span class="form-control-feedback" asp-validation-for="Firstname"> This field has an error. </span>

属性 Firstname 在 ViewModel 中有一个 Required 属性。

它是这样工作的:

<label class="control-label" asp-for="Firstname">Firstname</label>
<input type="text" class="form-control" asp-for="Firstname">
@Html.ValidationMessageFor(x => x.Firstname)

编辑:

如果我不将自定义错误消息添加到 Html 元素而是添加到 ViewModel DataAnnotation,它似乎可以工作,如下所示:

<label class="control-label" asp-for="Firstname">Firstname</label>
<input type="text" class="form-control" asp-for="Firstname">
<span class="form-control-feedback" asp-validation-for="Firstname"></span>

型号:

[Required(ErrorMessage = "This field has an error.")]
public string Firstname { get; set; }

TL;DR:

考虑在您确实需要某些东西的情况下将文本放入标签助手中 与生成的值不同。

完整答案

你几乎可以自己找到解决方案,但我想我仍然可以在这里投入我的两分钱。

大多数标签助手的工作方式都是在内容为空或仅包含空白字符的情况下生成内容。例如,ValidationMessageTagHelper 以这种方式检查它:

var tagHelperContent = await output.GetChildContentAsync();

// We check for whitespace to detect scenarios such as:
// <span validation-for="Name">
// </span>
if (!tagHelperContent.IsEmptyOrWhiteSpace)
{
    message = tagHelperContent.GetContent();
}

获取标签内容,如果内容为 null、空或空格,则填充 message 变量。然后使用 message 变量生成验证消息:

var tagBuilder = Generator.GenerateValidationMessage(
    ViewContext,
    For.ModelExplorer,
    For.Name,
    message: message,
    tag: null,
    htmlAttributes: htmlAttributes);

如果 messagenull 或为空则 DefaultHtmlGeneratorgenerator will provide the model error (see line 858);

if (!string.IsNullOrEmpty(message))
{
    tagBuilder.InnerHtml.SetContent(message);
}
else if (modelError != null)
{
    modelExplorer = modelExplorer ?? ExpressionMetadataProvider.FromStringExpression(
        expression,
        viewContext.ViewData,
        _metadataProvider);
    tagBuilder.InnerHtml.SetContent(
        ValidationHelpers.GetModelErrorMessageOrDefault(modelError, entry, modelExplorer));
}

GetModelErrorMessageOrDefault() of ValidationHelpers:

public static string GetModelErrorMessageOrDefault(
    ModelError modelError,
    ModelStateEntry containingEntry,
    ModelExplorer modelExplorer)
{
    Debug.Assert(modelError != null);
    Debug.Assert(containingEntry != null);
    Debug.Assert(modelExplorer != null);

    if (!string.IsNullOrEmpty(modelError.ErrorMessage))
    {
        return modelError.ErrorMessage;
    }

    // Default in the ValidationMessage case is a fallback error message.
    var attemptedValue = containingEntry.AttemptedValue ?? "null";
    return modelExplorer.Metadata.ModelBindingMessageProvider.ValueIsInvalidAccessor(attemptedValue);
}

所以是的,如果您在 <span> 验证标签内放置任何文本,标签助手将选择您的文本而不是来自模型状态的验证错误。如果您将文本放入 <label> 标记内,则会发生类似的行为:

<label class="control-label" asp-for="Firstname">Firstname</label>

标签助手不会覆盖您放入标签中的 Firstname 值。它可能看起来不是坏行为,但如果您想为 Firstname 属性:

使用显示名称
[Display(Name = "Fancy first name")]
public string Firstname { get; set; }

不会看到它起作用!因为标签助手会再次选择您在 Firstname.

的显示名称上放置 in-between <label> 标签的文本

你应该做的是尽可能简单:

<label class="control-label" asp-for="Firstname"></label>

考虑在您确实需要某些东西的情况下将文本放入标签助手中 与生成的值不同。

一开始我就说过大多数标签助手都是这样工作的。他们中的大多数人都这样做,但不是全部。例如 SelectTagHelper 允许您在标签内放置任何自定义文本,如果您提供 select 列表,它将通过将选项附加到现有内容来生成选项。添加自定义 <option> 标签非常方便。例如,我可以轻松添加 selected 和禁用选项,因此下拉列表没有初始值,因此用户被迫手动 select 一个选项。这些代码行:

<select asp-for="LevelId" asp-items="@Model.Levels" class="custom-select">
    <option selected disabled>Select option</option>
</select>

将导致:

<select class="custom-select" data-val="true" data-val-required="&#x27;Level Id&#x27; must not be empty." id="LevelId" name="LevelId">
    <option selected disabled>Select parking level</option>
    <option value="9">-2</option>
    <option value="8">-1</option>
    <option value="7">0</option>
</select>