ASP .Net Core 自定义标记帮助程序将 CamelCase 属性转换为空格
ASP .Net Core Custom Tag Helper to Convert CamelCase Properties to spaces
是否可以在 ASP.Net Core 中自动转换视图模型中的驼峰式大小写 属性 名称,以便在使用标签助手时将 spaces 插入到相应的标签中?
如果我的视图模型是这样的...
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "Referral Date")]
public DateTime ReferralDate { get; set; }
似乎有很多额外的配置应用数据注释,例如
[Display(Name = "First Name")]
在单词之间简单地插入一个space。 Tag Helpers 默认插入 space 以避免这种手动配置和潜在的拼写错误是有道理的。
如果不能,自定义标签助手能否在这种情况下提供帮助?如果可以,它是如何工作的?
您可以通过构建和注册自定义显示元数据提供程序来实现此目的。有些库会对 属性 名称执行更详尽的 "humanization",但您可以使用一些可靠的正则表达式实现一些非常有用的东西。
public class HumanizerMetadataProvider : IDisplayMetadataProvider
{
public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
{
var propertyAttributes = context.Attributes;
var modelMetadata = context.DisplayMetadata;
var propertyName = context.Key.Name;
if (IsTransformRequired(propertyName, modelMetadata, propertyAttributes))
{
modelMetadata.DisplayName = () => SplitCamelCase(propertyName);
}
}
private static string SplitCamelCase(string str)
{
return Regex.Replace(
Regex.Replace(
str,
@"(\P{Ll})(\P{Ll}\p{Ll})",
" "
),
@"(\p{Ll})(\P{Ll})",
" "
);
}
private static bool IsTransformRequired(string propertyName, DisplayMetadata modelMetadata, IReadOnlyList<object> propertyAttributes)
{
if (!string.IsNullOrEmpty(modelMetadata.SimpleDisplayProperty))
return false;
if (propertyAttributes.OfType<DisplayNameAttribute>().Any())
return false;
if (propertyAttributes.OfType<DisplayAttribute>().Any())
return false;
if (string.IsNullOrEmpty(propertyName))
return false;
return true;
}
}
IsTransformRequired
方法确保您仍然可以在需要时使用修饰的 属性 覆盖提供程序。
通过 IMvcBuilder
上的 AddMvcOptions
方法在启动时注册提供程序:
builder.AddMvcOptions(m => m.ModelMetadataDetailsProviders.Add(new HumanizerMetadataProvider()));
如果你只关心label,你可以轻松覆盖LabelTagHelper。
[HtmlTargetElement("label", Attributes = "title-case-for")]
public class TitleCaseTagHelper : LabelTagHelper
{
public TitleCaseTagHelper(IHtmlGenerator generator) : base(generator)
{
}
[HtmlAttributeName("title-case-for")]
public new ModelExpression For { get; set; }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
throw new ArgumentNullException("context");
if (output == null)
throw new ArgumentNullException("output");
string name = For.ModelExplorer.Metadata.DisplayName ?? For.ModelExplorer.Metadata.PropertyName;
name = name.Humanize(LetterCasing.Title);
TagBuilder tagBuilder = this.Generator.GenerateLabel(
this.ViewContext,
this.For.ModelExplorer,
this.For.Name,
name,
(object) null);
if (tagBuilder == null)
return;
output.MergeAttributes(tagBuilder);
if (output.IsContentModified)
return;
TagHelperContent childContentAsync = await output.GetChildContentAsync();
if (childContentAsync.IsEmptyOrWhiteSpace)
output.Content.SetHtmlContent((IHtmlContent) tagBuilder.InnerHtml);
else
output.Content.SetHtmlContent((IHtmlContent) childContentAsync);
}
}
用法
<label title-case-for="RememberMe" class="col-md-2 control-label"></label>
请确保放置using语句和@addTagHelper里面_ViewImports.cshtml.
@using YourNameSpace.Helpers
@addTagHelper *, YourNameSpace
备注
我用Humanizer English Only NuGet Package - Humanizer.Core。它比编写我自己的方法更健壮。如果你不喜欢开销,你可以只使用正则表达式。
如何使用自定义属性并覆盖 DisplayNameAttribute
public class DisplayWithSpace : DisplayNameAttribute
{
public DisplayWithSpace([System.Runtime.CompilerServices.CallerMemberName] string memberName ="")
{
Regex r = new Regex(@"(?!^)(?=[A-Z])");
DisplayNameValue = r.Replace(memberName, " ");
}
}
你的 属性 将是
[DisplayWithSpace]
public string FatherName { get; set; }
是否可以在 ASP.Net Core 中自动转换视图模型中的驼峰式大小写 属性 名称,以便在使用标签助手时将 spaces 插入到相应的标签中?
如果我的视图模型是这样的...
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "Referral Date")]
public DateTime ReferralDate { get; set; }
似乎有很多额外的配置应用数据注释,例如
[Display(Name = "First Name")]
在单词之间简单地插入一个space。 Tag Helpers 默认插入 space 以避免这种手动配置和潜在的拼写错误是有道理的。
如果不能,自定义标签助手能否在这种情况下提供帮助?如果可以,它是如何工作的?
您可以通过构建和注册自定义显示元数据提供程序来实现此目的。有些库会对 属性 名称执行更详尽的 "humanization",但您可以使用一些可靠的正则表达式实现一些非常有用的东西。
public class HumanizerMetadataProvider : IDisplayMetadataProvider
{
public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
{
var propertyAttributes = context.Attributes;
var modelMetadata = context.DisplayMetadata;
var propertyName = context.Key.Name;
if (IsTransformRequired(propertyName, modelMetadata, propertyAttributes))
{
modelMetadata.DisplayName = () => SplitCamelCase(propertyName);
}
}
private static string SplitCamelCase(string str)
{
return Regex.Replace(
Regex.Replace(
str,
@"(\P{Ll})(\P{Ll}\p{Ll})",
" "
),
@"(\p{Ll})(\P{Ll})",
" "
);
}
private static bool IsTransformRequired(string propertyName, DisplayMetadata modelMetadata, IReadOnlyList<object> propertyAttributes)
{
if (!string.IsNullOrEmpty(modelMetadata.SimpleDisplayProperty))
return false;
if (propertyAttributes.OfType<DisplayNameAttribute>().Any())
return false;
if (propertyAttributes.OfType<DisplayAttribute>().Any())
return false;
if (string.IsNullOrEmpty(propertyName))
return false;
return true;
}
}
IsTransformRequired
方法确保您仍然可以在需要时使用修饰的 属性 覆盖提供程序。
通过 IMvcBuilder
上的 AddMvcOptions
方法在启动时注册提供程序:
builder.AddMvcOptions(m => m.ModelMetadataDetailsProviders.Add(new HumanizerMetadataProvider()));
如果你只关心label,你可以轻松覆盖LabelTagHelper。
[HtmlTargetElement("label", Attributes = "title-case-for")]
public class TitleCaseTagHelper : LabelTagHelper
{
public TitleCaseTagHelper(IHtmlGenerator generator) : base(generator)
{
}
[HtmlAttributeName("title-case-for")]
public new ModelExpression For { get; set; }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
throw new ArgumentNullException("context");
if (output == null)
throw new ArgumentNullException("output");
string name = For.ModelExplorer.Metadata.DisplayName ?? For.ModelExplorer.Metadata.PropertyName;
name = name.Humanize(LetterCasing.Title);
TagBuilder tagBuilder = this.Generator.GenerateLabel(
this.ViewContext,
this.For.ModelExplorer,
this.For.Name,
name,
(object) null);
if (tagBuilder == null)
return;
output.MergeAttributes(tagBuilder);
if (output.IsContentModified)
return;
TagHelperContent childContentAsync = await output.GetChildContentAsync();
if (childContentAsync.IsEmptyOrWhiteSpace)
output.Content.SetHtmlContent((IHtmlContent) tagBuilder.InnerHtml);
else
output.Content.SetHtmlContent((IHtmlContent) childContentAsync);
}
}
用法
<label title-case-for="RememberMe" class="col-md-2 control-label"></label>
请确保放置using语句和@addTagHelper里面_ViewImports.cshtml.
@using YourNameSpace.Helpers
@addTagHelper *, YourNameSpace
备注
我用Humanizer English Only NuGet Package - Humanizer.Core。它比编写我自己的方法更健壮。如果你不喜欢开销,你可以只使用正则表达式。
如何使用自定义属性并覆盖 DisplayNameAttribute
public class DisplayWithSpace : DisplayNameAttribute
{
public DisplayWithSpace([System.Runtime.CompilerServices.CallerMemberName] string memberName ="")
{
Regex r = new Regex(@"(?!^)(?=[A-Z])");
DisplayNameValue = r.Replace(memberName, " ");
}
}
你的 属性 将是
[DisplayWithSpace]
public string FatherName { get; set; }