2017-04-11 30 views
3

如果我有這樣的視圖模型:如何讓asp-for輸入標籤幫助程序生成camelCase名稱?

public class MyModel{ 
     public DateTime? StartDate {get;set;} 
} 

而且視圖上輸入標籤使用的ASP換標籤幫手,像這樣:

<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?

回答

4

在研究了@Bebben發佈的代碼和提供的鏈接後,我繼續深入研究了Asp.Net Core源代碼。我發現Asp.Net Core的設計人員提供了一些可擴展點,可以用來實現較低的camelCase idname值。

要做到這一點,我們需要實現自己的IHtmlGenerator,我們可以通過創建一個繼承自DefaultHtmlGenerator的自定義類來實現。然後在該課程中,我們需要重寫GenerateTextBox方法來固定套管。或者,我們也可以替代GenerateInput方法來修復所有輸入字段(不僅僅是輸入文本字段)的nameid屬性值的外殼,這是我選擇做的。作爲獎勵,我還覆蓋了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類,則需要在地方DefaultHtmlGenerator的註冊它的IoC容器。我們可以在啓動的ConfigureServices方法中執行此操作。cs通過以下兩行:

//Replace DefaultHtmlGenerator with CustomHtmlGenerator 
    services.Remove<IHtmlGenerator, DefaultHtmlGenerator>(); 
    services.AddTransient<IHtmlGenerator, CustomHtmlGenerator>(); 

很酷。我們不僅解決了在輸入字段中的idname套管問題,而且通過實施我們自己的定製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); 
    } 

} 
+0

你的回答讓我想到了我需要的是用點代替爲id生成的darn下劃線。應該注意的是,你使用的'services.Remove ()'不是一個內置的擴展,必須單獨創建,或者至少據我所知,似乎是這樣。 – Gup3rSuR4c

+1

感謝您的評論。好點子。我將更新我的答案與該服務的代碼.Remove擴展方法。 –

2

做,這是隻寫

<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基金會)

該生產線是「對於。名稱」。該名稱被髮送到其他一些方法中,最後給出的最終名稱是一個靜態類(Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.NameAndIdProvider),所以我們無法輕鬆插入。

+1

您的回答激發了我深入研究源代碼,並發現可以實現系統範圍的方法。這是我第一次真正開始欣賞使用IoC容器的系統構建的強大功能。 –

+0

@RonC這是一個好消息:-) – Bebben