在研究了@Bebben 发布的代码和提供的链接之后,我继续深入挖掘 Asp.Net Core 源代码。而且我发现 Asp.Net Core 的设计者提供了一些扩展点,可以利用这些点来实现更低的驼峰式 id 和 name 值。
为此,我们需要实现我们自己的IHtmlGenerator,我们可以通过创建一个继承自DefaultHtmlGenerator 的自定义类来实现。然后在那个类上,我们需要重写GenerateTextBox 方法来修复大小写。或者,我们可以覆盖GenerateInput 方法来修复所有输入字段(不仅仅是输入文本字段)的name 和id 属性值的大小写,这是我选择做的。作为奖励,我还覆盖了 GenerateLabel 方法,因此标签的 for 属性也使用自定义大小写指定了一个值。
课程如下:
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Text.Encodings.Web;
namespace App.Web {
public class CustomHtmlGenerator : DefaultHtmlGenerator {
public CustomHtmlGenerator(
IAntiforgery antiforgery,
IOptions<MvcViewOptions> optionsAccessor,
IModelMetadataProvider metadataProvider,
IUrlHelperFactory urlHelperFactory,
HtmlEncoder htmlEncoder,
ClientValidatorCache clientValidatorCache) : base
(antiforgery, optionsAccessor, metadataProvider, urlHelperFactory,
htmlEncoder, clientValidatorCache) {
//Nothing to do
}
public CustomHtmlGenerator(
IAntiforgery antiforgery,
IOptions<MvcViewOptions> optionsAccessor,
IModelMetadataProvider metadataProvider,
IUrlHelperFactory urlHelperFactory,
HtmlEncoder htmlEncoder,
ClientValidatorCache clientValidatorCache,
ValidationHtmlAttributeProvider validationAttributeProvider) : base
(antiforgery, optionsAccessor, metadataProvider, urlHelperFactory, htmlEncoder,
clientValidatorCache, validationAttributeProvider) {
//Nothing to do
}
protected override TagBuilder GenerateInput(
ViewContext viewContext,
InputType inputType,
ModelExplorer modelExplorer,
string expression,
object value,
bool useViewData,
bool isChecked,
bool setId,
bool isExplicitValue,
string format,
IDictionary<string, object> htmlAttributes) {
expression = GetLowerCamelCase(expression);
return base.GenerateInput(viewContext, inputType, modelExplorer, expression, value, useViewData,
isChecked, setId, isExplicitValue, format, htmlAttributes);
}
public override TagBuilder GenerateLabel(
ViewContext viewContext,
ModelExplorer modelExplorer,
string expression,
string labelText,
object htmlAttributes) {
expression = GetLowerCamelCase(expression);
return base.GenerateLabel(viewContext, modelExplorer, expression, labelText, htmlAttributes);
}
private string GetLowerCamelCase(string text) {
if (!string.IsNullOrEmpty(text)) {
if (char.IsUpper(text[0])) {
return char.ToLower(text[0]) + text.Substring(1);
}
}
return text;
}
}
}
现在我们有了 CustomHtmlGenerator 类,我们需要在 IoC 容器中注册它来代替 DefaultHtmlGenerator。我们可以通过以下两行在 Startup.cs 的 ConfigureServices 方法中做到这一点:
//Replace DefaultHtmlGenerator with CustomHtmlGenerator
services.Remove<IHtmlGenerator, DefaultHtmlGenerator>();
services.AddTransient<IHtmlGenerator, CustomHtmlGenerator>();
很酷。我们不仅解决了输入字段上的id 和name 大小写问题,而且通过实现我们自己的自定义IHtmlGenerator 并注册它,我们打开了可以完成各种html 自定义的大门.
我开始真正欣赏围绕 IoC 构建的系统的强大功能,以及带有虚拟方法的默认类。在这种方法下不费吹灰之力就能实现的定制水平非常惊人。
更新
@Gup3rSuR4c 指出我的 services.Remove 调用必须是框架中未包含的扩展方法。我查了一下,是的,确实如此。所以,这里是那个扩展方法的代码:
public static class IServiceCollectionExtensions {
public static void Remove<TServiceType, TImplementationType>(this IServiceCollection services) {
var serviceDescriptor = services.First(s => s.ServiceType == typeof(TServiceType) &&
s.ImplementationType == typeof(TImplementationType));
services.Remove(serviceDescriptor);
}
}