打包多CSS或JS文件以加快页面加载速度的Handl

打包多CSS或JS文件以加快页面加载速度的Handl

ASP.NET 打包多CSS或JS文件以加快页面加载速度的Handler,

使用<link type="text/css" rel="Stylesheet" href="HttpCombiner.ashx?" />,具体的参数请参考程序中的介绍。附件

using System;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Services; namespace SLTech.DST.Web.Application
{
/// <summary>
/// Summary description for $codebehindclassname$
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class HttpCombiner : IHttpHandler
{
private const bool DO_GZIP = true;
private readonly static TimeSpan CACHE_DURATION = TimeSpan.FromDays(30);
private const string DEFAULT_CSS = "decision-support-toolkit.css,controls/tab.css,controls/extension-button.css,"; public void ProcessRequest(HttpContext context)
{
var request = context.Request; // Read setName, contentType and version.
//All are required. They are used as cache key
var setName = request["s"] ?? string.Empty;
var contentType = request["t"] ?? string.Empty;
var version = request["v"] ?? string.Empty;
var files = request["f"] ?? string.Empty;
files = DEFAULT_CSS + files; // Decide if browser supports compressed response
var isCompressed = DO_GZIP && this.CanGZip(context.Request); // Response is written as UTF8 encoding.
var encoding = new UTF8Encoding(false); // If the set has already been cached, write the response directly from
// cache. Otherwise generate the response and cache it
if (!this.WriteFromCache(context, setName, version, isCompressed, contentType))
{
using (var memoryStream = new MemoryStream(5000))
{
// Decide regular stream or GZipStream based on whether the response
// can be cached or not
using (var writer = isCompressed ?
(Stream)(new GZipStream(memoryStream, CompressionMode.Compress)) :
memoryStream)
{
// Load the files defined and process each file
var fileNames = files.Split(new char[] { ',' },
StringSplitOptions.RemoveEmptyEntries); foreach (string fileName in fileNames)
{
var fileBytes = this.GetFileBytes(context,"css/"+fileName.Trim(), encoding);
writer.Write(fileBytes, 0, fileBytes.Length);
} writer.Close();
} var responseBytes = memoryStream.ToArray();
context.Cache.Insert(GetCacheKey(setName, version, isCompressed),
responseBytes, null, System.Web.Caching.Cache.NoAbsoluteExpiration,
CACHE_DURATION); // Generate the response
this.WriteBytes(responseBytes, context, isCompressed, contentType);
}
}
} private byte[] GetFileBytes(HttpContext context, string virtualPath, Encoding encoding)
{
if (virtualPath.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase))
{
using (var client = new WebClient())
{
return client.DownloadData(virtualPath);
}
}
else
{
var physicalPath = context.Server.MapPath(virtualPath);
var bytes = File.ReadAllBytes(physicalPath);
return bytes;
}
} private bool WriteFromCache(HttpContext context, string setName, string version,
bool isCompressed, string contentType)
{
var responseBytes = context.Cache[GetCacheKey(setName, version, isCompressed)] as byte[]; if (null == responseBytes || 0 == responseBytes.Length) return false; this.WriteBytes(responseBytes, context, isCompressed, contentType);
return true;
} private void WriteBytes(byte[] bytes, HttpContext context,
bool isCompressed, string contentType)
{
var response = context.Response; response.AppendHeader("Content-Length", bytes.Length.ToString());
response.ContentType = contentType;
if (isCompressed)
response.AppendHeader("Content-Encoding", "gzip"); context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetExpires(DateTime.Now.Add(CACHE_DURATION));
context.Response.Cache.SetMaxAge(CACHE_DURATION);
context.Response.Cache.AppendCacheExtension("must-revalidate, proxy-revalidate"); response.OutputStream.Write(bytes, 0, bytes.Length);
response.Flush();
} private bool CanGZip(HttpRequest request)
{
var acceptEncoding = request.Headers["Accept-Encoding"];
return (!string.IsNullOrEmpty(acceptEncoding) &&
(acceptEncoding.Contains("gzip") || acceptEncoding.Contains("deflate")));
} private string GetCacheKey(string setName, string version, bool isCompressed)
{
return "HttpCombiner." + setName + "." + version + "." + isCompressed;
} public bool IsReusable
{
get
{
return false;
}
}
}
}
05-06 08:37