Extending Controller for Better Ajax Support

First blog post ever! Let’s see how it’ll turn out.

So I’ve been playing with Html & Js for a while as it’s the “cool” thing these days. It was all working fine , a few Ajax calls here and there etc. But after a while , I noticed this one weird or maybe even buggy behavior.

There is this one controller where I check out the incoming requests and if everything is OK then I redirect it to another action. And then in that second action I want to check if it’s an Ajax request or not , since I just want to send back raw page ( without Master Page ) if it is indeed an Ajax request.

When I did that , I thought my first action would run and just switch to the second action when it comes to RedirectToAction.

But it turns out when you use RedirectToAction method , MVC actually finishes the first Action , even fires up the OnResultExecuting / OnResultExecuted method and then starts a new procedure , creates a new controller and runs that second action etc.

Well OK , what’s the problem? The problem is , the request I’m working on is an Ajax request. But when I redirect to that second action , using RedirectToAction() , the second action runs as if the request is just an ordinary ( non-Ajax ) request. So when you go check Request.IsAjaxRequest() in that second action , you’ll get a huge , sad FALSE. Long story shorter ; RedirectToAction loses the Ajax Flag!

After Googling about it a little , I found a StackOverflow Q&A for this issue. Unfortunately I can’t seem to find it at the moment but I’ll add the link whenever I do. The suggested and accepted solution was extending the default controller to preserve the Ajax flag by using TempData. Obviously TempData is a great fit for the job as it’s created and used to store information that can be consumed in subsequent requests , right?

Unfortunately there were some little bugs with the suggested solution in that Stackoverflow Q&A so I just write my own little custom controller for it.

Enough with the talk eh?

 

 

public class FaschoController : Controller
{
    private const string AjaxTempKey = "__isAjax";
    public bool IsAjax
    {
        get
        {
            return (Request.IsAjaxRequest() || TempData.ContainsKey(AjaxTempKey));
        }
    }

    private void PreserveAjaxFlag()
    {
        if (IsAjax)
        {
            TempData[AjaxTempKey] = true;
        }
        else if (TempData.ContainsKey(AjaxTempKey))
        {
            TempData.Remove(AjaxTempKey);
        }
    }

    protected override void OnResultExecuting(ResultExecutingContext filterContext)
    {

        if (filterContext.Result is RedirectToRouteResult)
        {
            PreserveAjaxFlag();
        }

        base.OnResultExecuting(filterContext);
    }
}

 

 

First of all , I’m really bad at naming stuff so I just go with the first thing came to my mind. And what are we doing here , extending , strengthening the “Controller” right? THE Controller… So yeah , Fascho Controller! It’s silly I know, anyway…

So what’s going on here? We just override the OnResultExecuting method and make sure that it saves the Ajax flag to somewhere safe ( well safer than a controller which will be destroyed in seconds ) in case it’s a RedirectToRouteResult.

protected override void OnResultExecuting(ResultExecutingContext filterContext)
{
    if(filterContext.Result is RedirectToRouteResult)
    {
        PreserveAjaxFlag();
    }
    base.OnResultExecuting(filterContext);
}

Remember we’re still in first action so Request.IsAjaxRequest() will return true. Then we put this answer into TempData with a static key defined in our controller.

private void PreserveAjaxFlag()
{
    if (IsAjax)
    {
        TempData[AjaxTempKey] = true;
    }
    else if (TempData.ContainsKey(AjaxTempKey))
    {
        TempData.Remove(AjaxTempKey);
    }
}

And we’re done with the first action! Now when MVC redirect to second action , you’ll see that standard Request.IsAjaxRequest() will return FALSE but if you check our new IsAjax property , it’ll go check and return the TempData value we saved earlier. And NOW you can handle the request properly in your second action!

One more thing tho , it may or may not be necessary ( depending on your project ) but I also like to remove that Ajax key in TempData myself , just in case.

 

if(filterContext.Result is ViewResult)
{
    TempData.Remove(AjaxTempKey);
}

If you add this to OnResultExecuting part , it’ll remove the key whenever our application returns a view , which generally means we’re kinda done with the request and returned a proper response.

I’ll extend FaschoController even more in future , there are some other stuff I want to throw in Controller , mainly just to clean my Actions and get ride of some repetitive logic.

Visual Studio 2010 Solution

Leave a Reply