Взять имя представления из реального имени действия, а не из ActionNameAttribute?

[ActionName("new-post")]
public async Task<IActionResult> NewPost()
{
    return View();
}

В этом примере ASP.NET Core будет искать представление по имени "new-post", но я хочу, чтобы оно искало по реальному имени действия, которое "NewPost". В ASP.NET MVC 5 я сделал это с помощью фильтра, в котором было сохранено имя представления (filterContext.Result as ViewResultBase).ViewName. В ASP.NET Core 2.0 фильтры IAsyncActionFilter используются для асинхронных действий и контекста. Результат всегда равен нулю, поэтому я не могу изменить имя представления через него. Есть ли другие возможные способы сделать это? Конечно, я мог бы передать имя представления в return View(), но это было бы избыточным дублированием уже известного имени действия.

1 ответ

Я обнаружил, что IActionFilter может использоваться как для синхронных, так и для асинхронных действий: http://jakeydocs.readthedocs.io/en/latest/mvc/controllers/filters.html

В контексте IActionFilter.Result доступен, так что теперь я могу заставить ASP.NET Core 2.0 принимать реальное имя действия следующим образом:

public class SetActionViewNameFromActionNameAttributeFilter : IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext context)
    {
        var result = context.Result as ViewResult;

        if (result != null)
        {
            var controllerActionDescriptor = (ControllerActionDescriptor)context.ActionDescriptor;
            var actionNameAttr = controllerActionDescriptor.MethodInfo.TryGetAttribute<ActionNameAttribute>();

            bool changeViewName = actionNameAttr != null && (result.ViewName == null || result.ViewName == actionNameAttr.Name);

            if (changeViewName)
                result.ViewName = controllerActionDescriptor.MethodInfo.Name;
        }
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
    }
}

Если бы кто-то предложил более элегантный способ, я был бы признателен.

Другие вопросы по тегам