ASP.NET MVC - compression + caching
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 compr开发者_如何学Goessed 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.
[Compress]
[OutputCache(Duration = 600, VaryByParam = "*", VaryByContentEncoding="gzip;deflate")]
public ActionResult Index()
{
return View();
}
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.
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
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")]
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;
}
}
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.
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());
精彩评论