11

I've seen a number of options for adding GZIP/DEFLATE compression to ASP.Net MVC output, but they all seem to apply the compression on-the-fly.. thus do not take advange of caching the compressed content.

Any solutions for enabling caching of the compressed page output? Preferably in the code, so that the MVC code can check if the page has changed, and ship out the precompressed cached content if not.

This question really could apply to regular asp.net as well.

Brady Moritz
  • 8,624
  • 8
  • 66
  • 100
  • You mean like caching the compressed response in `System.Web.Cache`? – bzlm Oct 01 '10 at 12:15
  • Perhaps, or any other solutions which accomplish this. – Brady Moritz Oct 04 '10 at 20:12
  • None of the answers thus far, while informative in other respects, seem to address compressing content _in_ the cache vs. content _served from_ the cache. Thinking back to a UG presentation on ASP.NET caching, have you considered writing a custom cache provider? – J0e3gan May 08 '13 at 15:01
  • Linking this as a possible solution, but I have not tested it: http://weblogs.asp.net/rashid/archive/2008/03/28/asp-net-mvc-action-filter-caching-and-compression.aspx – AaronLS May 08 '13 at 18:52

7 Answers7

5
[Compress]
[OutputCache(Duration = 600, VaryByParam = "*", VaryByContentEncoding="gzip;deflate")]
public ActionResult Index()
{
    return View();
}
AlDev
  • 173
  • 1
  • 7
3

Use caching options using attributes (for MVC), and do not think about compression since IIS/IISExpress automatically compresses your output if you enable it.

the way it works, mvc does not enable caching of individual fragments or parts of output (partial content caching). if you want this, consider using a service like CloudFlare (is there any other like CF?). it automatically caches your output and caches fragments of your output and provides many other performance and security improvements, all without a change in your code.

If this is not an option for you, then you still may use IISpeed (it is a IIS port of Google's mod_pagespeed). It provides some interesting settings like whitespace removal, inline css and js compression, js file merge and many other.

Both CF and IISpeed does not care how your site is built, they work on http/html level, so they both work on MVC, Classic ASP.NET, php or even raw html files.

Erdogan Kurtur
  • 3,630
  • 21
  • 39
1

You can create a attribute like

public class EnableCompressionAttribute : ActionFilterAttribute  
{  
    const CompressionMode Compress = CompressionMode.Compress;  

    public override void OnActionExecuting(ActionExecutingContext filterContext)  
    {  
        HttpRequestBase request = filterContext.HttpContext.Request;  
        HttpResponseBase response = filterContext.HttpContext.Response;  
        string acceptEncoding = request.Headers["Accept-Encoding"];  
        if (acceptEncoding == null)  
            return;  
        else if (acceptEncoding.ToLower().Contains("gzip"))  
        {  
            response.Filter = new GZipStream(response.Filter, Compress);  
            response.AppendHeader("Content-Encoding", "gzip");  
        }  
        else if (acceptEncoding.ToLower().Contains("deflate"))  
        {  
            response.Filter = new DeflateStream(response.Filter, Compress);  
            response.AppendHeader("Content-Encoding", "deflate");  
        }  
    }  
} 

Add entry in Global.asax.cs

        public static void RegisterGlobalFilters(GlobalFilterCollection filters)  
        {  
            filters.Add(new EnableCompressionAttribute());  
        }  

Then you can use this attribute as:

    [EnableCompression]
    public ActionResult WithCompression()
    {
        ViewBag.Content = "Compressed";
        return View("Index");
    }

You can download working example from Github: https://github.com/ctesene/TestCompressionActionFilter

Pranav Singh
  • 17,079
  • 30
  • 77
  • 104
  • This supports **caching** the compressed version of the page instead of recompressing each request? – AaronLS May 08 '13 at 18:49
  • Yes, the attribute is applied to controller method thus "response" is compressed from server side. I didn't get what do you mean by "re-compressing the request". – Pranav Singh May 11 '13 at 23:04
  • Whether or not the compression occurs on every request and is thus inefficient: "Request Received->Retrieve Cached page->Compress cached page", versus just "Request Received->Retrieve Cached page(which is already compressed)". – AaronLS May 12 '13 at 01:17
  • I still don't get the actual need or use-case. If the request is cached, the server responds with a 304 status code and does not send the document body to the client, it means no server hit to get cached resource until it's changed on server when request is made. Compression is done on response not on request. what's actual issue you want to get resolved??? – Pranav Singh May 12 '13 at 01:32
  • If the page is cached, it should be cached in its compressed form. It is wasteful to recompress the same content on every request. – AaronLS May 12 '13 at 01:56
  • I'm not talking about client side caching, I'm talking about server side caching. – AaronLS May 12 '13 at 01:58
1

This link seems fairly close to what you require. It caches compressed dynamically generated pages. Although the example uses Web forms, It can be adapted to MVC by using an OutputCache attribute

[OutputCache(Duration = 600, VaryByParam = "*", VaryByContentEncoding="gzip;deflate")]
rivarolle
  • 1,528
  • 11
  • 18
0

You could create a Cache Attribute:

public class CacheAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;

        if (Enabled)
        {
            cache.SetExpires(System.DateTime.Now.AddDays(30));
        }
        else
        {
            cache.SetCacheability(HttpCacheability.NoCache);
            cache.SetNoStore();
        }
    }

    public bool Enabled { get; set; }

    public CacheAttribute()
    {
        Enabled = true;
    }
}
Jonathan Bates
  • 1,835
  • 14
  • 22
  • How does this handle compression? – Brady Moritz Aug 29 '12 at 04:17
  • Sorry, misunderstood that part of the question. You could check this out http://weblogs.asp.net/rashid/archive/2008/03/28/asp-net-mvc-action-filter-caching-and-compression.aspx. It is still doing on the fly compression, but its attribute-based giving you more of a pick and choose option that a server-wide solution. – Jonathan Bates Aug 29 '12 at 14:29
0

See Improving performance with output caching for a full introduction on the subject. The main recommendation is to use the [OutputCache] attribute on the Action to which caching should be applied.

Yaakov Ellis
  • 40,752
  • 27
  • 129
  • 174
0

use namespace

using System.Web.Mvc;

using System.IO.Compression;

create ClassName.cs in you main project

public class CompressAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {

            var _encodingsAccepted = filterContext.HttpContext.Request.Headers["Accept-Encoding"];
            if (string.IsNullOrEmpty(_encodingsAccepted)) return;

            _encodingsAccepted = _encodingsAccepted.ToLowerInvariant();
            var _response = filterContext.HttpContext.Response;
if(_response.Filter == null) return;
            if (_encodingsAccepted.Contains("deflate"))
            {
                _response.AppendHeader("Content-encoding", "deflate");
                _response.Filter = new DeflateStream(_response.Filter, CompressionMode.Compress);
            }
            else if (_encodingsAccepted.Contains("gzip"))
            {
                _response.AppendHeader("Content-encoding", "gzip");
                _response.Filter = new GZipStream(_response.Filter, CompressionMode.Compress);
            }
        }
    }

--- and add in global.asax.cs

GlobalFilters.Filters.Add(new CompressAttribute());