Search code examples
asp.net-mvc-3custom-attributesaction-filter

MVC3: Is it possible to change the result type outside of the code of the action itself?


If I create an controller method that returns ActionResult, then call View() at the end, is there any way to have a Filter (or something simular) change the returned result from the ViewResult emitted by View() to a PartialViewResult based on conditions in the Request?

Clearly I can have code in the controller method itself that returns the ViewResult or PartialViewResult, but this comes up in a number of places so it seems like a good use of a Filter. I tried doing this in both methods of the IResultFilter and saw no change in the output.

If this is not possible then I will look at creating some methods in my base controller called something like ViewOrPartial that I can call instead of View, but I wanted to seek broader wisdom before giving up on the Filter (or something like it) approach.

Thanks, Matthew

Update: So it appears that at least one difference between what I had tried and what is now working based on Darin's code is that I had overridden OnResultExecuting (and I had also tried OnResultExecuted) and Darin's code overrides OnActionExecuted. Does that seem odd or am I perhaps overlooking something else? I am delighted to have it working but it seemed to make more sense that to attach it to the IResultFilter interface. I will have to look into the intention of the two interfaces more.


Solution

  • Yes, it is possible:

    public class MyActionFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            var result = filterContext.Result;
            var viewResult = result as ViewResult;
            var someValue = filterContext.Controller.ValueProvider.GetValue("someValue");
            if (viewResult != null && someValue != null && someValue.AttemptedValue == "foo")
            {
                // if the controller action returned a view result
                // and the someValue parameter equals foo we replace the 
                // view result initially returned by the action by a 
                // partial view result
                var partialResult = new PartialViewResult();
                partialResult.ViewData.Model = viewResult.Model;
                filterContext.Result = partialResult;
            }
        }
    }
    

    Then decorate:

    [MyActionFilter]
    public ActionResult Foo()
    {
        MyViewModel vm = ...
        return View(vm);
    }