如果我有这样的视图模型:
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?
答案 0 :(得分:8)
在研究了@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
。我们可以通过以下两行在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);
}
}
答案 1 :(得分: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)
该行是&#34; For.Name&#34;。该名称被发送到其他一些方法,最后给出最终名称的方法是在静态类(Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.NameAndIdProvider)中,所以我们无法轻易插入任何内容。