Изучив код, опубликованный @Bebben, и ссылку на него, я продолжил копаться в исходном коде Asp.Net Core. И я обнаружил, что разработчики Asp.Net Core предоставили некоторые точки расширяемости, которые можно использовать для достижения более низких значений camelCase 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
. Мы можем сделать это в ConfigureServices
методе Startup.cs с помощью следующих двух строк:
//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);
}
}
person
RonC
schedule
13.04.2017