ASP.NET Core 2.0:自定义HtmlHelper丢失验证添加的CSS类如何解决?
嗨,这个问题我之前碰到过类似的情况,核心原因是你的自定义VTextBoxFor助手没有调用ASP.NET Core内置的客户端验证属性收集逻辑——默认的@Html.TextBoxFor内部会自动处理IClientModelValidator返回的HTML属性,但自定义助手需要你手动触发这个过程。
下面是具体的解决步骤和代码示例:
1. 从Expression获取ModelMetadata
首先,你需要通过传入的Expression<Func<TModel, TResult>>获取对应的模型元数据,这是获取验证相关信息的基础:
var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
2. 获取IClientModelValidator生成的客户端属性
ASP.NET Core提供了GetUnobtrusiveValidationAttributes方法,它会遍历所有注册的IClientModelValidator,收集它们生成的客户端验证属性(包括你添加的currency类):
var validationAttributes = htmlHelper.GetUnobtrusiveValidationAttributes(metadata.PropertyName, metadata);
3. 合并自定义HTML属性与验证属性
接下来,把你传入的自定义HTML属性和验证属性合并,重点处理class属性的追加(避免覆盖已有样式):
// 将匿名对象转为字典,方便操作 var combinedAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); foreach (var attr in validationAttributes) { if (attr.Key.Equals("class", StringComparison.OrdinalIgnoreCase)) { if (combinedAttributes.ContainsKey("class")) { // 追加验证类到已有class后面 combinedAttributes["class"] = $"{combinedAttributes["class"]} {attr.Value}"; } else { combinedAttributes["class"] = attr.Value; } } else { // 其他验证属性直接添加(比如data-val相关属性) combinedAttributes[attr.Key] = attr.Value; } }
4. 修改自定义VTextBoxFor方法
把上面的逻辑整合到你的VTextBoxFor方法中,最终生成Bootstrap风格的输入框时使用合并后的属性:
public static IHtmlContent VTextBoxFor<TModel, TResult>(this IHtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TResult>> expression, object htmlAttributes = null) { // 1. 获取模型元数据 var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); // 2. 获取客户端验证属性 var validationAttrs = htmlHelper.GetUnobtrusiveValidationAttributes(metadata.PropertyName, metadata); // 3. 合并属性 var combinedAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); foreach (var attr in validationAttrs) { if (attr.Key.Equals("class", StringComparison.OrdinalIgnoreCase)) { if (combinedAttributes.ContainsKey("class")) { combinedAttributes["class"] = $"{combinedAttributes["class"]} {attr.Value}"; } else { combinedAttributes["class"] = attr.Value; } } else { combinedAttributes[attr.Key] = attr.Value; } } // 4. 生成Bootstrap风格的输入框,这里可以根据你的需求调整 // 比如确保form-control类存在,同时包含验证类 if (!combinedAttributes.ContainsKey("class") || !combinedAttributes["class"].ToString().Contains("form-control")) { combinedAttributes["class"] = combinedAttributes.ContainsKey("class") ? $"{combinedAttributes["class"]} form-control" : "form-control"; } return htmlHelper.TextBoxFor(expression, combinedAttributes); }
额外说明:直接从Expression获取验证特性
如果你需要直接获取模型上的DataAnnotations验证特性(比如自定义的验证属性),可以通过ModelMetadata的ValidatorMetadata属性:
var serverValidationAttributes = metadata.ValidatorMetadata.OfType<ValidationAttribute>();
不过这是服务器端的验证特性集合,和你需要的客户端IClientModelValidator生成的HTML属性是两回事,所以优先用GetUnobtrusiveValidationAttributes来获取客户端属性。
这样修改后,你的VTextBoxFor就能像默认的TextBoxFor一样,保留IClientModelValidator添加的currency类了,同时也能正常适配Bootstrap样式。
内容的提问来源于stack exchange,提问作者chrisonstack

