asp.netgzipoutputcachedeflatecontent-encoding

OutputCache is not working if content encoding addded to header


I have a controller and an action in it.

public class LoginController
{
    [OutputCache(Duration = 10000, VaryByParam = "none")]
    public ActionResult Logout()
    {
        ......
    }
}

Above code is working and there is no problem with output cache. Everything is ok.

But when i added the code below to Application_BeginRequest something goes wrong. I added the picture of the page.

 string encodings = app.Request.Headers.Get("Accept-Encoding");
 if (encodings != null)
 {
            // Check the browser accepts deflate or gzip (deflate takes preference)
            encodings = encodings.ToLower();

            if (encodings.Contains("gzip"))
            {
                app.Response.Filter = new GZipStream(app.Response.Filter, CompressionMode.Compress);
                app.Response.AppendHeader("Content-Encoding", "gzip");
            }
            else if (encodings.Contains("deflate"))
            {
                app.Response.Filter = new DeflateStream(app.Response.Filter, CompressionMode.Compress);
                app.Response.AppendHeader("Content-Encoding", "deflate");
            }

 }

The page is ....


Solution

  • You have to add a VaryByContentEncoding.
    Without one, only 1 version gets cached.

    If this version in the cache has been constructed from a request supporting eg. gzip compression, this cached data will be compressed in gzip format.
    This same compressed data will then also be served to requests that don't support compression or only deflate, which results into what you see.

    You must ensure that separate versions get cached; 1 non compressed, 1 for gizp and another for deflate.
    Doing so allows that the correct version will be served according to what the webbrowser supports.

    [OutputCache(Duration = 10000, VaryByParam = "none", VaryByContentEncoding="gzip;deflate")]
    public ActionResult Logout()
    {
        // ...
    }
    

    EDIT

    Besides the missing VaryByContentEncoding, there's more going on.

    The Application_BeginRequest isn't 'playing nice' with the OutputCacheAttribute.
    Because of this, the cache duration doesn't get applied anymore. This must have to do with the order of execution and which headers get set at which moment.

    Instead of relying on Application_BeginRequest move the compression code to an action filter, which for ASP.NET MVC is the advised way to act within the request pipeline.
    See the CompressAttribute below.

    By means of example, I applied it to the out-of-the box About method on the HomeController.
    This time, the results are as expected matching the request and response http-headers.

    CompressAttribute:

    public class CompressAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            HttpRequestBase request = filterContext.RequestContext.HttpContext.Request;
            HttpResponseBase response = filterContext.RequestContext.HttpContext.Response;
    
            string encodings = request.Headers.Get("Accept-Encoding");
            if (encodings != null)
            {
                // Check the browser accepts deflate or gzip (deflate takes preference)
                encodings = encodings.ToLower();
    
                if (encodings.Contains("gzip"))
                {
                    response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
                    response.AppendHeader("Content-Encoding", "gzip");
                }
                else if (encodings.Contains("deflate"))
                {
                    response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
                    response.AppendHeader("Content-Encoding", "deflate");
                }
            }
        }
    }
    

    HomeController:

    public class HomeController : Controller
    {
        [Compress()]
        [OutputCache(Duration = 10, VaryByParam = "none", VaryByContentEncoding="gzip;deflate")]
        public ActionResult About()
        {
            ViewBag.Message = DateTime.Now.ToString("dd/MM/yy HH:mm:ss.fff");
            return View();
        }        
    }