Tag Helper asp-validation-for始终显示

时间:2019-06-01 16:52:56

标签: asp.net asp.net-core tag-helpers

我尝试使用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; }

1 个答案:

答案 0 :(得分:1)

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

它获取标签内容,然后填充message变量(如果内容为null,空白或空白)。然后,message变量用于生成验证消息:

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

如果messagenull或为空,则generator将提供模型错误(请参阅DefaultHtmlGenerator的{​​{3}});

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

line 858中的GetModelErrorMessageOrDefault()

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

不会看到它起作用!因为标签助手会再次选择您在<label>的显示名称上方插入Firstname标签之间的文本。

您应该做的就是尽可能简单:

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

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

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

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