Вспомогательная функция настраиваемого тега ASP .Net Core для преобразования свойств CamelCase в пробелы

Возможно ли в ASP.Net Core автоматически преобразовывать имена свойств верблюжьего регистра в моделях представлений для вставки пробелов в соответствующие метки при использовании помощников тегов?

Если моя модель представления выглядит так ...

[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")]

просто вставить пробел между словами. Было бы разумно, чтобы помощники тегов вставляли пробел по умолчанию, чтобы избежать этой ручной настройки и возможных опечаток.

Если нет, может ли помощник настраиваемого тега помочь в этой ситуации, и если да, то как он будет работать?


person OjM    schedule 20.03.2017    source источник


Ответы (3)


Вы можете добиться этого, создав и зарегистрировав настраиваемого поставщика метаданных отображения. Существуют библиотеки, которые будут выполнять более сложную «гуманизацию» имен свойств, но вы можете добиться чего-то довольно полезного с помощью некоторых надежных регулярных выражений.

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})",
                "$1 $2"
            ),
            @"(\p{Ll})(\P{Ll})",
            "$1 $2"
        );
    }

    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 гарантирует, что вы по-прежнему можете переопределить поставщика с декорированным свойством, когда вам нужно.

Зарегистрируйте провайдера при запуске с помощью метода AddMvcOptions на IMvcBuilder:

builder.AddMvcOptions(m => m.ModelMetadataDetailsProviders.Add(new HumanizerMetadataProvider()));
person Polynomial    schedule 20.03.2017
comment
это работает, но привело меня к этой ссылке для полного объяснения, а также мне нужно было установить этот пакет nuget по ссылке - person OjM; 21.03.2017
comment
@ojm Спасибо за ссылку на Humanizer. Именно то, что я искал. - person Auspex; 15.03.2019
comment
Как это настроить в приложении ASP.NET Core 3.0? - person Ciaran Gallagher; 26.01.2020
comment
Я пробовал ваш код, но, похоже, он не сработал, когда я попробовал его на странице Razor - person Ciaran Gallagher; 26.01.2020
comment
Также не сработало, когда я попробовал через стандартный контроллер и действие? - person Ciaran Gallagher; 31.01.2020

Если вас интересует только 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 Пакет NuGet только на английском языке - Humanizer.Core. Это более надежно, чем написание моего собственного метода. Если вам не нравятся накладные расходы, вы можете просто использовать регулярное выражение.

person Win    schedule 20.03.2017

как насчет использования настраиваемого атрибута и переопределения 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; }
person Usman    schedule 20.03.2017