如果我有这样的视图模型:
- public class MyModel{
- public DateTime? StartDate {get;set;}
- }
在视图上,输入标记与asp-for标记助手一起使用,如下所示:
- <input asp-for="StartDate" />
由此生成的默认html是
- <input type="datetime" id="StartDate" name="StartDate" value="" />
但我希望它生成的是html,如下所示:
- <input type="datetime" id="startDate" name="startDate" value="" />
如何让asp-for输入标签帮助器生成像上面这样的驼峰案例名称,而不必使我的模型属性为camelCase?
最佳答案
在研究了@Bebben发布的代码及其提供的链接后,我继续深入研究Asp.Net Core源代码.我发现Asp.Net Core的设计者提供了一些可扩展性点,可用于实现更低的camelCase id和名称值.
为此,我们需要实现自己的IHtmlGenerator,我们可以通过创建一个继承自DefaultHtmlGenerator的自定义类来实现.然后在该类上我们需要覆盖GenerateTextBox方法来修复外壳.或者我们可以覆盖GenerateInput方法来修复所有输入字段(不仅仅是输入文本字段)的name和id属性值的大小写,这是我选择做的.作为奖励,我还覆盖了GenerateLabel方法,因此标签的属性也使用自定义套管指定值.
这是班级:
- 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,ClientValidatorCache clientValidatorCache,ValidationHtmlAttributeProvider validationAttributeProvider) : base
- (antiforgery,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,string labelText,object htmlAttributes) {
- expression = GetLowerCamelCase(expression);
- return base.GenerateLabel(viewContext,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和名称外壳问题,而且通过实现我们自己的自定义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);
- }
- }