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; }