3

I looked to make extension method to HTML Helper to show the Description for the property of my ViewModel. Here the listing, because since How do I display the DisplayAttribute.Description attribute value? things have changed in ASP.NET Core 3.1.

Here is my extension method:

public static string DescriptionFor<TModel, TValue>(this IHtmlHelper<TModel> self, Expression<Func<TModel, TValue>> expression) {
    MemberExpression memberExpression = (MemberExpression)expression.Body;
    var displayAttribute = (DisplayAttribute)memberExpression.Member.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault();
    string description = displayAttribute?.Description ?? memberExpression.Member?.Name;
    //But how can i localize this description
    return description;
}

But now I need localize it, like does, for instance

@Html.DisplayNameFor(model => model.MyNotObviousProperty)

How can I retrieve DataAnnotationLocalizer in my extension method? Of course, I can pass it like the argument, but it is not beautiful solution, when DisplayNameFor not asks for additional arguments.

Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
dmi
  • 122
  • 1
  • 5

1 Answers1

1

You just need to get a reference to IStringLocalizer.

In your startup:

public void Configure(..., IStringLocalizer stringLocalizer) // ASP.NET Core will inject it for you
{
    // your current code
    YourExtensionsClass.RegisterLocalizer(stringLocalizer);
}

and in your extensions class:

public static class YourExtensionsClass
{
    private static IStringLocalizer _localizer;

    public static void RegisterLocalizer(IStringLocalizer localizer)
    {
        _localizer = localizer;
    }

    public static string DescriptionFor<TModel, TValue>(this IHtmlHelper<TModel> self, Expression<Func<TModel, TValue>> expression) 
    {
        MemberExpression memberExpression = (MemberExpression)expression.Body;
        var displayAttribute = (DisplayAttribute)memberExpression.Member.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault();
        string description = displayAttribute?.Description ?? memberExpression.Member?.Name;
        
        return _localizer[description];
    }
}

If you want more control, I'd suggest you to get some ideas from how ASP.NET Core does internally, by taking a look at the source code (method CreateDisplayMetadata).

Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
  • Thank you! I have my own IStringLocalizerFactory to translate type to suitable resource location, because default convention of resources' files locations is not very comfortable for my project. So i changed the method: description = _LocalizerFactory.Create(memberExpression.Expression.Type)[description]; – dmi Aug 08 '20 at 11:38