Замена ExpressionHelper в ASP.NET Core 3.0?

В ASP.NET Core 2.x я использовал статический метод GetExpressionText класса ExpressionHelper для IHtmlHelper<T> метода расширения:

using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;

public static class HtmlHelperExtensions
{
    public static string GetExpressionText<TModel, TResult>(
        this IHtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TResult>> expression)
    {
        return ExpressionHelper.GetExpressionText(expression);
    }
}

В ASP.NET Core 3.0 пространство имен Microsoft.AspNetCore.Mvc.ViewFeatures.Internal больше не доступно. Поэтому компилятор выдает исключение:

Имя ExpressionHelper не существует в текущем контексте.

Что является правильной заменой ExpressionHelper функциональности?


person Nenad    schedule 06.09.2019    source источник


Ответы (2)


ModelExpressionProvider из Microsoft.AspNetCore.Mvc.ViewFeatures можно использовать.

Метод GetExpressionText объединяет идентичный метод ExpressionHelper и добавляет дополнительное кеширование или результаты, как описано в этой проблеме Github.

using Microsoft.AspNetCore.Mvc.ViewFeatures;

public static class HtmlHelperExtensions
{
    public static string GetExpressionText<TModel, TResult>(
        this IHtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TResult>> expression)
    {
        var expresionProvider = htmlHelper.ViewContext.HttpContext.RequestServices
            .GetService(typeof(ModelExpressionProvider)) as ModelExpressionProvider;

        return expresionProvider.GetExpressionText(expression);
    }
}
person Nenad    schedule 06.09.2019
comment
Будет ли это работать, если не использовать View? Как для API. Я не уверен, зачем нужен какой-либо ViewContext для GetExpressionText. - person Victorio Berra; 10.03.2020
comment
GetExpressionText в основном используется для отображения идентификаторов и имен элементов HTML с целью привязки модели, поэтому расширение для IHtmlHelper ‹TModel› подходит для большинства случаев использования. Вы также можете использовать его из API. Все, что вам нужно, это получить экземпляр ModelExpressionProvider. Самым простым, вероятно, было бы получить его через внедрение зависимостей в конструкторе контроллера. - person Nenad; 11.03.2020
comment
Спасибо. Мой вариант использования немного сложнее. Мне это действительно нужно в профиле автомаппера. К сожалению, профили, зарегистрированные с помощью встроенного сканирования сборок, не поддерживают инъекции. У них должен быть пустой конструктор. Итак, я только что нашел другие фрагменты для выполнения того, что мне нужно, а именно преобразования цепочки свойств выражения в строку, которая немного проще, чем getexpressiontext. - person Victorio Berra; 11.03.2020

Альтернативное решение, которое не зависит от IHtmlHelper и может использоваться в других сценариях, следующее:

public static class StringExtensions
{
    private static readonly ModelExpressionProvider ModelExpressionProvider = new ModelExpressionProvider(new EmptyModelMetadataProvider());

    public static string GetExpressionText<TEntity, TProperty>(this Expression<Func<TEntity, TProperty>> expression)
    {
        return ModelExpressionProvider.GetExpressionText(expression);
    }
}

Следует иметь в виду, что ModelExpressionProvider содержит внутри ConcurrentDictionary для кеширования, поэтому сделать его статическим может быть полезно.

Как сказал Ненад, ModelExpressionProvider.GetExpressionText - это просто оболочка вокруг ExpressionHelper.GetExpressionText с добавлением параметра кеша:

public class ModelExpressionProvider : IModelExpressionProvider
{
    private readonly IModelMetadataProvider _modelMetadataProvider;
    private readonly ConcurrentDictionary<LambdaExpression, string> _expressionTextCache;
    ....
    public string GetExpressionText<TModel, TValue>(Expression<Func<TModel, TValue>> expression)
    {
        if (expression == null)
        {
            throw new ArgumentNullException(nameof(expression));
        }

        return ExpressionHelper.GetExpressionText(expression, _expressionTextCache);
    }
    ....
}
person Augusto Barreto    schedule 18.04.2020