首页 文章

如何让asp-for输入标签helper生成camelCase名称?

提问于
浏览
4

如果我有这样的视图模型:

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?

2 回答

  • 6

    在研究了@Bebben发布的代码及其提供的链接后,我继续深入研究Asp.Net Core源代码 . 我发现Asp.Net Core的设计者提供了一些可扩展性点,可用于实现更低的camelCase idname 值 .

    要做到这一点,我们需要实现我们自己的 IHtmlGenerator ,我们可以通过创建一个继承自 DefaultHtmlGenerator 的自定义类来实现 . 然后在那个类上我们需要覆盖 GenerateTextBox 方法来修复外壳 . 或者我们可以覆盖 GenerateInput 方法来修复所有输入字段(不仅仅是输入文本字段)的 nameid 属性值的大小写,这是我选择做的 . 作为奖励,我还覆盖 GenerateLabel 方法,因此标签的 for 属性也使用自定义套管指定值 .

    这是 class :

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

    很酷 . 我们不仅解决了输入字段上的 idname 外壳问题,而且通过实现我们自己的自定义 IHtmlGenerator ,并使其注册,我们打开了可以完成的各种html自定义的大门 .

    我开始非常欣赏围绕IoC构建的系统的强大功能,以及使用虚拟方法的默认类 . 在这种方法下可以轻松获得的定制水平真的非常惊人 .

    Update
    @ 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); 
        }
    
    }
    
  • 4

    最简单的方法就是写

    <input asp-for="StartDate" name="startDate" />
    

    或者你想让它在驼峰的情况下完全自动生成,对于整个应用程序?

    为此,您似乎必须在Microsoft.AspNetCore.Mvc.TagHelpers中实现自己的InputTagHelpers .

    以下是生成名称的方法:

    private TagBuilder GenerateTextBox(ModelExplorer modelExplorer, string inputTypeHint, string inputType)
    {
        var format = Format;
        if (string.IsNullOrEmpty(format))
        {
            format = GetFormat(modelExplorer, inputTypeHint, inputType);
        }
    
        var htmlAttributes = new Dictionary<string, object>
        {
            { "type", inputType }
        };
    
        if (string.Equals(inputType, "file") && string.Equals(inputTypeHint, TemplateRenderer.IEnumerableOfIFormFileName))
        {
            htmlAttributes["multiple"] = "multiple";
        }
    
        return Generator.GenerateTextBox(
            ViewContext,
            modelExplorer,
            For.Name,
            value: modelExplorer.Model,
            format: format,
            htmlAttributes: htmlAttributes);
    }
    

    (上面的代码来自https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.TagHelpers/InputTagHelper.cs,Apache许可证,版本2.0,版权所有.NET Foundation)

    该行是“For.Name” . 该名称被发送到其他一些方法,最后给出最终名称的方法是静态类(Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.NameAndIdProvider),所以我们无法轻易插入 .

相关问题