Internet Explorer displaying cache data over Ajax Pull with 304 Result

2.8k views Asked by At

I have a tool that works perfectly fine in Chrome and FF. But with any versions of IE the browser is displaying cache info over doing an Ajax pull to retrieve the data.

Here's my setup:

I have criterias that I loop through:

@foreach (var item in Model)
{
        <div class="sizeTDCriteria">
            @Html.DisplayFor(modelItem => item.Text)
        </div>
        <div class="sizeTDCriteriaAction">
            @Ajax.ImageActionLink(Url.Content("~/Content/images/icons/edit.png"), "Edit Criteria", "AddOrEditCriteria", "Management", new { competencySectionId = ViewBag.competencySectionId, criteriaId = item.Id }, new AjaxOptions { UpdateTargetId = "AddOrEditCriteriaFormContainer" }, new { @class = "iconPosition" })
            @Ajax.ImageActionLink(Url.Content("~/Content/images/icons/delete.png"), "Delete Criteria", "RemoveCriteria", "Management", new { criteriaId = item.Id }, new AjaxOptions { UpdateTargetId = "CompetenciesManagementWrapper" }, new { @class = "iconPosition" })
        </div>
}

The ImageActionLink is just a helper that creates a ActionLink with an image inside, I've tried doing this with a normal ActionLink and the issue occurs as well so you can ignore that. I've also tried to change the whole ImageActionLink by a plain <img> with a jQuery trigger with no difference.

What happens is that when a user clicks on the Edit link it will do an ajax call to the "AddOrEditCriteria", that ActionResult, finds the criteria, and displays the PartialView form back into the div "#AddOrEditCriteriaFormContainer". So far so good, this works fine in all browsers.

But when I click a second time on that edit, instead of doing the ajax call, IE simply displays the PartialView from what it had in the cache, when all other browsers correctly pull the data again (which is required, as that view allows to edit the criterias, it could have been edited by someone else in the mean time).

The weird part is that IE is making the call but somehow it never reaches the server, it just uses the cache by using a Result 304. You can see from this Network capture:

URL Method  Result  Type    Received    Taken   Initiator   Wait??  Start?? Request??   Response??  Cache read??    Gap??
/PerformanceMVC/Management/AddOrEditCriteria?competencySectionId=178&criteriaId=369&X-Requested-With=XMLHttpRequest GET 304 text/html   182 B   < 1 ms  JS Library XMLHttpRequest
/PerformanceMVC/Management/AddOrEditCriteria?competencySectionId=178&criteriaId=369&X-Requested-With=XMLHttpRequest GET 304 text/html   182 B   < 1 ms  JS Library XMLHttpRequest
/PerformanceMVC/Management/AddOrEditCriteria?competencySectionId=178&criteriaId=369&X-Requested-With=XMLHttpRequest GET 200 text/html   1.53 KB 1.24 s  JS Library XMLHttpRequest

The last one is the first to happen, the first two were done after and are getting a 304 return.

I found a way to fix it by adding a "breakcache" parameter to the ajax call with a random number, but that just doesn't seem like a good solution.

This issue has been screwing our users because they see data that should is not updated all because of IE.

1

There are 1 answers

7
Craig Stuntz On BEST ANSWER

IE will cache AJAX GETs unless you tell it not to.

You tell it not to via the Cache-Control header.

So here's what we do:

[CacheControl(HttpCacheability.NoCache), HttpGet]
public ActionResult MyAction() { return Json("Hi!", JsonRequestBehavior.AllowGet); }

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class CacheControlAttribute : ActionFilterAttribute
{
    public CacheControlAttribute(HttpCacheability cacheability)
    {
        this._cacheability = cacheability;
    }

    public HttpCacheability Cacheability { get { return this._cacheability; } } 

    private HttpCacheability _cacheability;

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
        cache.SetCacheability(_cacheability);
    }
}