ASP.NET MVC - compression + caching
Asked Answered
I

7

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.

Involve answered 30/9, 2010 at 18:33 Comment(4)
You mean like caching the compressed response in System.Web.Cache?Restful
Perhaps, or any other solutions which accomplish this.Involve
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?Nickens
Linking this as a possible solution, but I have not tested it: weblogs.asp.net/rashid/archive/2008/03/28/…Minstrelsy
D
5
[Compress]
[OutputCache(Duration = 600, VaryByParam = "*", VaryByContentEncoding="gzip;deflate")]
public ActionResult Index()
{
    return View();
}
Dyadic answered 16/10, 2010 at 17:57 Comment(3)
Any documentation on this? looks like exactly what Im after.Involve
I'd love to see more info on this, I havent been able to make the "Compress" attrib workInvolve
@BradyMoritz it's possible the Compress attribute is being referenced to something like the following https://mcmap.net/q/64439/-how-to-gzip-content-in-asp-net-mvcOcclude
M
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.

Margarethe answered 7/5, 2013 at 12:56 Comment(1)
one last one, be careful when you use Vary since it may break caching behavior of some old IE versions.Margarethe
T
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

Tolmann answered 8/5, 2013 at 6:22 Comment(6)
This supports caching the compressed version of the page instead of recompressing each request?Minstrelsy
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".Tolmann
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)".Minstrelsy
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???Tolmann
If the page is cached, it should be cached in its compressed form. It is wasteful to recompress the same content on every request.Minstrelsy
I'm not talking about client side caching, I'm talking about server side caching.Minstrelsy
J
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")]
Jaehne answered 8/5, 2013 at 21:13 Comment(0)
A
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;
    }
}
Annamarieannamese answered 16/10, 2010 at 18:10 Comment(2)
How does this handle compression?Involve
Sorry, misunderstood that part of the question. You could check this out weblogs.asp.net/rashid/archive/2008/03/28/…. 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.Annamarieannamese
I
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.

Ivory answered 17/10, 2010 at 10:21 Comment(1)
Don't see mention of compression though?Involve
D
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());
Dozen answered 9/6, 2021 at 13:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.