gpt4 book ai didi

asp.net-core - EditorFor Tag Helper 在使用 FluentValidator 时不呈现验证属性

转载 作者:行者123 更新时间:2023-12-03 14:47:59 27 4
gpt4 key购买 nike

我有一个像这样的简单表单,它使用了@Html.EditorFor 扩展:

<form method="post">
@Html.EditorFor(x => x.SystemSettings.EmailFromAddress)
<submit-button title="Save"></submit-button>
</form>

我想利用 .NET Core 的标签助手,让我的表单看起来像这样:
<form method="post">
<editor asp-for="SystemSettings.EmailFromAddress"/>
<submit-button title="Save"></submit-button>
</form>

我最终也想拥有自己的自定义标签助手,这样我就可以做这样的事情:
<text-box asp-for="SystemSettings.EmailFromAddress"></text-box>

我有一个由 @Html.EditorFor 扩展呈现的字符串模板:
@model string
<div class="form-group">
<label asp-for="@Model" class="m-b-none"></label>
<span asp-description-for="@Model" class="help-block m-b-none small m-t-none"></span>
<div class="input-group">
<input asp-for="@Model" class="form-control" />
<partial name="_ValidationIcon" />
</div>
<span asp-validation-for="@Model" class="validation-message"></span>
</div>

为此,我看到有人实现了 编辑标签助手 ,看起来像这样:
[HtmlTargetElement("editor", TagStructure = TagStructure.WithoutEndTag,
Attributes = ForAttributeName)]
public class EditorTagHelper : TagHelper
{
private readonly IHtmlHelper _htmlHelper;

private const string ForAttributeName = "asp-for";
private const string TemplateAttributeName = "asp-template";

[HtmlAttributeName(ForAttributeName)]
public ModelExpression For { get; set; }


[HtmlAttributeName(TemplateAttributeName)]
public string Template { get; set; }

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

public EditorTagHelper(IHtmlHelper htmlHelper)
{
_htmlHelper = htmlHelper;
}

public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
throw new ArgumentNullException(nameof(context));

if (output == null)
throw new ArgumentNullException(nameof(output));

if (!output.Attributes.ContainsName(nameof(Template)))
{
output.Attributes.Add(nameof(Template), Template);
}

output.SuppressOutput();

(_htmlHelper as IViewContextAware).Contextualize(ViewContext);

output.Content.SetHtmlContent(_htmlHelper.Editor(For.Name, Template));

await Task.CompletedTask;
}
}

但是,当我使用 EditorTagHelper 时,它似乎缺少不显眼的 Javascript 验证属性:

使用 @Html.EditorFor ,这被渲染:
<input class="form-control valid" type="text" data-val="true" data-val-required="Email From Address cannot be empty" id="SystemSettings_EmailFromAddress" name="SystemSettings.EmailFromAddress" value="whatever@test.com" aria-required="true" aria-invalid="false" aria-describedby="SystemSettings_EmailFromAddress-error">

它具有 data-val 属性,因此可以应用客户端验证。

当我使用 编辑标签助手 相反,这会被渲染:
<input class="form-control valid" type="text" id="SystemSettings_EmailFromAddress" name="SystemSettings.EmailFromAddress" value="whatever@test.com" aria-invalid="false">

未应用不显眼的验证属性。我正在使用 FluentValidation 并且我指定了这样的 AbstractValidator:
public class SystemSettingsValidator : AbstractValidator<SystemSettings>
{
public SystemSettingsValidator()
{
RuleFor(x => x.EmailFromAddress).NotEmpty()
.WithMessage("Email From Address cannot be empty");
}
}

我发现如果我删除了 AbstractorValidator 并简单地向我的模型属性添加了一个 [Required] 属性,那么验证就会正常工作。这表明 FluentValidation 有问题。可能存在配置问题。

我正在使用 Autofac 依赖注入(inject)来扫描我的程序集并注册验证器类型:
builder.RegisterAssemblyTypes(Assembly.Load(assembly))
.Where(t => t.IsClosedTypeOf(typeof(IValidator<>)))
.AsImplementedInterfaces()
.PropertiesAutowired()
.InstancePerLifetimeScope();

这似乎工作正常。如果它不好,我还尝试从流式验证选项中注册验证器,如下所示:
.AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblies(new List<Assembly>
{Assembly.GetExecutingAssembly(), Assembly.Load(nameof(Entities))});
})

这似乎也很好。

需要注意的一点是,我之前遇到的一个问题是,当包含标签助手时,使用 Autofac 程序集扫描会破坏应用程序。我添加了一个过滤器以确保在注册这些依赖项时不包含标签助手,例如
builder.RegisterAutowiredAssemblyInterfaces(Assembly.Load(Web))
.Where(x => !x.Name.EndsWith("TagHelper"));

我在这里上传了代码的工作示例: https://github.com/ciaran036/coresample2

导航到 Settings Page查看我要验证的字段。

此问题似乎也会影响 View 组件。

谢谢。

最佳答案

我相信问题出在标签助手中,因为它使用 IHtmlHelper.Editor而不是 IHtmlHelper<TModel>.EditorFor生成 HTML 内容。它们并不完全相同。

正如您所指出的,FluentValidation 会按照您对 @Html.EditorFor(x => x.SystemSettings.EmailFromAddress) 的期望注入(inject)验证属性。 .然而对于 @Html.Editor("SystemSettings.EmailFromAddress") ,这是您的自定义标签助手正在做的事情,FluentValidation 不会注入(inject)验证属性。这样就排除了标签助手本身并将问题转移到 Editor调用。

我还注意到 Editor无法解决 <label asp-for (或您正在使用的其他 <span asp-description-for 标签助手),这表明这不是 FluentValidation 特定的问题。

我无法通过 Required 复制您的成功自定义标签助手的属性/Editor - Required属性仅在使用 EditorFor 时注入(inject)验证属性.
Editor 的内部结构和 EditorFor相似但有一个关键区别,它们解决 ModelExplorer 的方式用于生成 HTML 内容的实例不同,我怀疑这是问题所在。有关这些差异,请参见下文。

Editor vs EditorFor ModelExplorer

PropertyName 这样的事情设置为 null 和 Metadata.Property未设置为 Editor , 但设置为 EmailFromAddressSystemSettings.EmailFromAddress对于 EditorFor是我们所看到的行为的潜在原因。

痛苦的部分是标签助手有一个有效的 ModelExplorer实例通过 For属性(property)。但是没有内置规定将其提供给 html 帮助程序。

至于分辨率,显而易见的似乎是使用 EditorFor而不是 Editor但是看起来并不容易。它可能涉及反射(reflection)和建立表达。

另一种选择是,考虑到标签助手解析 ModelExplorer正确,是扩展 HtmlHelper并覆盖 GenerateEditor方法 - 两者都是EditorEditorFor最终调用 - 因此您可以传入 ModelExplorer 并解决问题。

public class CustomHtmlHelper : HtmlHelper, IHtmlHelper
{
public CustomHtmlHelper(IHtmlGenerator htmlGenerator, ICompositeViewEngine viewEngine, IModelMetadataProvider metadataProvider, IViewBufferScope bufferScope, HtmlEncoder htmlEncoder, UrlEncoder urlEncoder) : base(htmlGenerator, viewEngine, metadataProvider, bufferScope, htmlEncoder, urlEncoder) { }

public IHtmlContent CustomGenerateEditor(ModelExplorer modelExplorer, string htmlFieldName, string templateName, object additionalViewData)
{
return GenerateEditor(modelExplorer, htmlFieldName, templateName, additionalViewData);
}

protected override IHtmlContent GenerateEditor(ModelExplorer modelExplorer, string htmlFieldName, string templateName, object additionalViewData)
{
return base.GenerateEditor(modelExplorer, htmlFieldName, templateName, additionalViewData);
}
}

更新您的标签助手以使用它:
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
throw new ArgumentNullException(nameof(context));

if (output == null)
throw new ArgumentNullException(nameof(output));

if (!output.Attributes.ContainsName(nameof(Template)))
{
output.Attributes.Add(nameof(Template), Template);
}

output.SuppressOutput();

(_htmlHelper as IViewContextAware).Contextualize(ViewContext);

var customHtmlHelper = _htmlHelper as CustomHtmlHelper;
var content = customHtmlHelper.CustomGenerateEditor(For.ModelExplorer, For.Metadata.DisplayName ?? For.Metadata.PropertyName, Template, null);
output.Content.SetHtmlContent(content);

await Task.CompletedTask;
}

最后注册新的助手,越早越好
services.AddScoped<IHtmlHelper, CustomHtmlHelper>();

Working solution

关于asp.net-core - EditorFor Tag Helper 在使用 FluentValidator 时不呈现验证属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60078465/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com