views:

370

answers:

3

Looks like I'm about to do something weird again...

The situation:

public ExperimentAttribute
{
    public override void OnActionExecuted (ActionExecutingContext filterContext)
    {
        filterContext.Result =
                    new RedirectToRouteResult (
                        new RouteValueDictionary (new { Action = "Action2", Controller = "Experiment" }));
    }
}

public ExperimentController
{
    [Experiment]
    public ActionResult ExperimentEntryPoint ()
    {
        RedirectToAction ("Action1", "Experiment");
    }

    public ActionResult Action1 ()
    {
        /* ... */
    }

    public ActionResult Action2 ()
    {
        /* ... */
    }
}

So, which redirect will take place? The one in controller action, the one in ActionFilter or maybe both?

A: 

They can't both happen as they both return a HTTP 302 redirect.

The attribute will execute the redirect since it's the last thing to happen before the result is sent to the client. Both OnActionExecuting and OnActionExecuted will happen over top of the controller's action result.

Chad Moran
Cheers, I'll delete my answer now Mastermind has concluded his experiment. Sounds like a strange case to me though.
Mark Dickinson
I agree, it logically doesn't make sense.
Chad Moran
+1  A: 

So I've just conducted an experiment that confirmed what I expected.

ExperimentEntryPoint returns an ActionResult, namely redirect to Action1.

OnActionExecuted overwrites the result before the rest of framework gets to process it. When it comes to it, it sees the redirect to Action2 command.

Nice and clear.

User
A: 

I can't think of a reason (YET! -- I can think of a few reasons you might want to do it in OnActionExecuting(), before your Action method code executes) for changing the ActionResult using filterContext.Result in the OnActionExecuting() method, but it is definitely allowed.

The order of execution is:

  • OnActionExecuting()
  • Your Action method code in your Controller
  • OnActionExecuted()
  • OnResultExecuting()
  • Whatever the assigned ActionResult.ExecuteResult() returns (renders a view, json, content, etc)
  • OnResultExecuted()

As your experiment showed, you're allowed to change filterContext.Result in both OnActionExecuted() and also OnActionExecuting(). Since OnActionExecuted() is called after your Controller code (example: return RedirectToAction()), whatever it sets as the ActionResult takes precedence.

I found decent coverage of ActionFilters in Steven Sanderson's book 'Pro ASP.NET MVC framework'. [1] [2]

[1] http://books.google.com/books?id=Xb3a1xTSfZgC (The content on ActionFilters is not available in the Google Book Preview)

[2] http://blog.codeville.net/2009/04/29/now-published-pro-aspnet-mvc-framework-apress/