Taking a view name from a real action name not from ActionNameAttribute?

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

In this example, ASP.NET Core will look for a view by name "new-post", but I want it to look for by real action name which is "NewPost". In ASP.NET MVC 5 I did it with a filter where the name of view was stored in (filterContext.Result as ViewResultBase).ViewName. In ASP.NET Core 2.0 IAsyncActionFilter filters are used for async actions and context.Result is always null there, so I can't change the view name via it anymore. Are there any other possible ways to do it? Of course, I could pass the view name into return View() but it would be a redundant duplication of already known action name.

1

There are 1 best solutions below

0
On

I found that IActionFilter can be used for both synchronious and asynchronious actions: http://jakeydocs.readthedocs.io/en/latest/mvc/controllers/filters.html#action-filters

In IActionFilter context.Result is available so now I can make ASP.NET Core 2.0 take a real action name this way:

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)
    {
    }
}

If someone suggested a more elegant way I would appreciate it.