您的位置:首页 > 编程语言 > ASP

web优化之-Asp.net MVC js、css动态合并 动态压缩 (2)

2012-10-17 14:06 801 查看
在前一篇文章web优化之-Asp.net MVC js、css动态合并 动态压缩中的js和css的路径都是Scripts/jquery-1.5.1.js,Scripts/jquery.validate.js这在http请求时路径比较长,为此我们可以改用[Scripts/jquery-1.5.1,jquery.validate]这种格式。同时为了防止文件更新后客户端无法刷新的问题我们加了version标记

修改后的代码:

CombineFiles:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.IO;
using Yahoo.Yui.Compressor;

/// <summary>
/// Summary description for CombineFiles
/// </summary>
public class CombineFiles : IHttpHandler
{

public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/javascript";
HttpRequest request = context.Request;
HttpResponse response = context.Response;
string[] allkeys = request.QueryString.AllKeys;
string version = string.Empty;
if (allkeys.Contains("version"))
{
version = request.QueryString["version"].Trim().ToLower();
}
if (!allkeys.Contains("href") || !allkeys.Contains("type") || !allkeys.Contains("compress"))
{
response.Write("请求格式不正确,正确格式是type=....&href=....&compress=...\r\n");
response.Write("type只能是js或则css,compress只能是true或则false,href则是请求的文件,多个文件已逗号分隔\r\n");
response.Write("示例如下:\r\n type=js&compress=true&href=[Scripts/jquery-1.5.1,jquery.validate][Scripts/MicrosoftAjax]");
}
else
{
string cacheKey = request.Url.Query;
#region /*确定合并文件类型*/
string fileType = request.QueryString["type"].Trim().ToLower();
string contenType = string.Empty;
if (fileType.Equals("js"))
{
contenType = "text/javascript";
}
else if (fileType.Equals("css"))
{
contenType = "text/css";
}
/*确定合并文件类型*/
#endregion
CacheItem cacheItem = HttpRuntime.Cache.Get(cacheKey) as CacheItem;//服务端缓存
if (cacheItem != null && !String.IsNullOrEmpty(cacheItem.Version) && !string.IsNullOrEmpty(version))
{
if (cacheItem.Version != version)
{
cacheItem = null;
}
}
if (cacheItem == null)
{
#region 合并压缩文件
/*合并文件*/
string href = context.Request.QueryString["href"].Trim();
string content = string.Empty;
string[] files = GetFilePath(href);
StringBuilder sb = new StringBuilder();
foreach (string fileName in files)
{

string filePath = context.Server.MapPath(fileName + "." + fileType);
if (File.Exists(filePath))
{
string readstr = File.ReadAllText(filePath, Encoding.UTF8);
sb.Append(readstr);
//content = JavaScriptCompressor.Compress(content);
//response.Write(content);
}
else
{
sb.AppendLine("\r\n未找到源文件" + filePath + "\r\n");
}
}
content = sb.ToString();
/*合并文件*/
/*压缩文件*/
string compressStr = request.QueryString["compress"].Trim();
bool iscompress = bool.Parse(compressStr);
if (iscompress)
{
if (fileType.Equals("js"))
{
//content = JavaScriptCompressor.Compress(content);
content = (new JavaScriptCompressor()).Compress(content);
}
else if (fileType.Equals("css"))
{
// content = CssCompressor.Compress(content);
content = (new CssCompressor()).Compress(content);
}
}
/*压缩文件*/
#endregion
cacheItem = new CacheItem() { Content = content, Expires = DateTime.Now.AddHours(1), Version = version };
HttpRuntime.Cache.Insert(cacheKey, cacheItem, null, cacheItem.Expires, TimeSpan.Zero);
}
response.ContentType = contenType;
if (request.Headers["If-Modified-Since"] != null && TimeSpan.FromTicks(cacheItem.Expires.Ticks - DateTime.Parse(request.Headers["If-Modified-Since"]).Ticks).Seconds < 100)
{
response.StatusCode = 304;
// response.Headers.Add("Content-Encoding", "gzip");
response.StatusDescription = "Not Modified";
}
else
{
response.Write(cacheItem.Content);
SetClientCaching(response, DateTime.Now);
}
}  //合并文件结束
}

string[] GetFilePath(string filesrc)
{
List<string> result = new List<string>();
string[] files = filesrc.Split(new char[] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string file in files)
{
string[] srcs = file.Split(new char[] { ',' });
string first = srcs[0];
int index = first.LastIndexOf("/");
string prefx = first.Substring(0, index);
result.Add(first);
if (srcs.Length > 1)
{
srcs = srcs.Where((x, i) => { return i > 0; }).Select(x => prefx + "/" + x).ToArray();
result.AddRange(srcs);
}
}
return result.ToArray();
}
private void SetClientCaching(HttpResponse response, DateTime lastModified)
{
response.Cache.SetETag(lastModified.Ticks.ToString());
response.Cache.SetLastModified(lastModified);
//public 以指定响应能由客户端和共享(代理)缓存进行缓存。
response.Cache.SetCacheability(HttpCacheability.Public);
//是允许文档在被视为陈旧之前存在的最长绝对时间。
response.Cache.SetMaxAge(new TimeSpan(7, 0, 0, 0));
//将缓存过期从绝对时间设置为可调时间
response.Cache.SetSlidingExpiration(true);
}
class CacheItem
{
public string Content { set; get; }
public DateTime Expires { set; get; }
public string Version { set; get; }
}
public bool IsReusable
{
get
{
return false;
}
}
}


CombineResFile:

namespace System.Web.Mvc.Html
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Text;
using System.Collections;
using System.IO;

public enum ResOrderType
{
Highest = 1,
High = 2,
Normal = 3,
Low = 4,
Lowest = 5
}
public enum ResourceType
{
/// <summary>
/// CSS
/// </summary>
StyleSheet = 0,

/// <summary>
/// JS
/// </summary>
Script = 1
}

public static class CombineResFile
{
class ResourceInfo
{
public string Url { set; get; }
public string Group { set; get; }
public ResOrderType Order { set; get; }
}
const string conAppendFileKey = "AppendFileKey";
const string conRemoveFileKey = "RemoveFileKey";
const string conRemoveGroupKey = "RemoveGroupKey";

/// <summary>
/// 合并路径
/// </summary>
/// <param name="paths"></param>
/// <returns></returns>

/// <summary>
/// 添加资源文件
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="resType">资源类型</param>
/// <param name="url">文件的路径</param>
/// <param name="group">文件的分组名称</param>
/// <param name="order">文件同组中的优先级,默认:Normal</param>
public static void AppendResFile(this HtmlHelper htmlHelper, ResourceType resType, string url, string group = "", ResOrderType order = ResOrderType.Normal)
{
AppendResFile(htmlHelper, resType, GetFilePath(url), group, order);
}

/// <summary>
/// 添加资源文件
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="resType">资源类型</param>
/// <param name="urls">文件的路径列表,如“channel/fanbuxie/urlcommon”,不支[]限定符</param>
/// <param name="group">文件的分组名称</param>
/// <param name="order">文件同组中的优先级,默认:Normal</param>
public static void AppendResFile(this HtmlHelper htmlHelper, ResourceType resType, string[] urls, string group = "", ResOrderType order = ResOrderType.Normal)
{
Dictionary<string, ResourceInfo> resFiles = null;
var urlArray = urls.Where(s => !string.IsNullOrWhiteSpace(s)).ToArray<string>();
if (urlArray == null || urlArray.Length == 0)
{
return;
}

string key = string.Format("{0}_{1}", resType.ToString(), conAppendFileKey);
if (htmlHelper.ViewContext.HttpContext.Items.Contains(key))
{
resFiles = htmlHelper.ViewContext.HttpContext.Items[key] as Dictionary<string, ResourceInfo>;
}
else
{
resFiles = new Dictionary<string, ResourceInfo>();
htmlHelper.ViewContext.HttpContext.Items.Add(key, resFiles);
}
for (int i = 0; i < urlArray.Length; i++)
{
if (resFiles.Keys.Contains(urlArray[i]))
{
resFiles[urlArray[i]].Group = group;
resFiles[urlArray[i]].Order = order;
}
else
{
resFiles.Add(urlArray[i], new ResourceInfo() { Url = urlArray[i], Group = group, Order = order });
}
}

htmlHelper.ViewContext.HttpContext.Items[key] = resFiles;
}

/// <summary>
/// 移除资源文件
/// </summary>
/// <param name="resType">资源类型</param>
/// <param name="htmlHelper"></param>
/// <param name="urls">移除文件,可以为空或则null </param>
/// <param name="group">移除文件所在的组可以为null</param>
public static void RemoveResFile(this HtmlHelper htmlHelper, ResourceType resType, string url, string group = "")
{
RemoveResFile(htmlHelper, resType, GetFilePath(url), group);
}
/// <summary>
/// 移除资源文件
/// </summary>
/// <param name="resType">资源类型</param>
/// <param name="htmlHelper"></param>
/// <param name="urls">移除文件列表,可以为空或则null </param>
/// <param name="group">移除文件所在的组可以为null</param>
public static void RemoveResFile(this HtmlHelper htmlHelper, ResourceType resType, string[] urls, string group = "")
{
var urlArray = urls.Where(s => !string.IsNullOrWhiteSpace(s)).ToArray<string>();

#region 按照js的地址移除
if (urlArray != null && urlArray.Length > 0)
{

List<string> removeFileKeys = null;
string key = string.Format("{0}_{1}", resType.ToString(), conRemoveFileKey);

if (htmlHelper.ViewContext.HttpContext.Items.Contains(key))
{
removeFileKeys = htmlHelper.ViewContext.HttpContext.Items[key] as List<string>;
}
else
{
removeFileKeys = new List<string>();
htmlHelper.ViewContext.HttpContext.Items.Add(key, removeFileKeys);
}
for (int i = 0; i < urlArray.Length; i++)
{
var url = urlArray[i].Trim().ToLower();
if (!removeFileKeys.Contains(url))
{
removeFileKeys.Add(url);
}
}
}
#endregion

#region  按照js的group移除
if (!string.IsNullOrEmpty(group))
{
List<string> removeGroupKeys = null;
string keyGroup = string.Format("{0}_{1}", resType.ToString(), conRemoveGroupKey);
if (htmlHelper.ViewContext.HttpContext.Items.Contains(keyGroup))
{
removeGroupKeys = htmlHelper.ViewContext.HttpContext.Items[keyGroup] as List<string>;
}
else
{
removeGroupKeys = new List<string>();
htmlHelper.ViewContext.HttpContext.Items.Add(keyGroup, removeGroupKeys);
}
if (!removeGroupKeys.Contains(group))
{
removeGroupKeys.Add(group);
}

}
#endregion
}
/// <summary>
/// 输出js
/// </summary>
/// <param name="htmlHelper"></param>
/// <returns></returns>
public static MvcHtmlString RenderResFile(this HtmlHelper htmlHelper, ResourceType resType)
{
string keyAppend = string.Format("{0}_{1}", resType.ToString(), conAppendFileKey);
string keyRemove = string.Format("{0}_{1}", resType.ToString(), conRemoveGroupKey);
string keyRemoveGroup = string.Format("{0}_{1}", resType.ToString(), conRemoveGroupKey);
Dictionary<string, ResourceInfo> resFiles = null;
StringBuilder content = new StringBuilder();
if (htmlHelper.ViewContext.HttpContext.Items.Contains(keyAppend))
{
resFiles = htmlHelper.ViewContext.HttpContext.Items[keyAppend] as Dictionary<string, ResourceInfo>;
List<string> removeFileKey = new List<string>();
if (htmlHelper.ViewContext.HttpContext.Items.Contains(keyRemove))
{
removeFileKey = htmlHelper.ViewContext.HttpContext.Items[keyRemove] as List<string>;
}
List<string> removeGroupKey = new List<string>();
if (htmlHelper.ViewContext.HttpContext.Items.Contains(keyRemoveGroup))
{
removeGroupKey = htmlHelper.ViewContext.HttpContext.Items[keyRemoveGroup] as List<string>;
}
List<ResourceInfo> files = resFiles.Select(x => x.Value)
.Where(x => !removeFileKey.Contains(x.Url) && !removeGroupKey.Contains(x.Group))
.ToList<ResourceInfo>();

IEnumerable<IGrouping<string, ResourceInfo>> jsGroupFiles = files.OrderByDescending(x => x.Group).GroupBy(x => x.Group);
foreach (IGrouping<string, ResourceInfo> item in jsGroupFiles)
{
var resPath = CombinePath(item.ToArray());
string version = "0";
//获取版本号
version = GetVersion(item.ToArray(), resType);

switch (resType)
{
case ResourceType.StyleSheet:
string cssformat = "<link charset=\"utf-8\" rel=\"stylesheet\" type=\"text/css\" href=\"/CombineFiles.ashx?type=js&compress=false&href={0}&version={1}\">";
content.Append(string.Format(cssformat, resPath, version));
break;

case ResourceType.Script:
string jsformat = "<script type=\"text/javascript\" src=\"/CombineFiles.ashx?type=js&compress=true&href={0}&version={1} \"></script>";
content.Append(string.Format(jsformat, resPath, version));
break;
}

}
}//end if
return new MvcHtmlString(content.ToString());
}

static string CombinePath(ResourceInfo[] items)
{
var all = items.OrderBy(x => x.Order).GroupBy(x => x.Order).ToArray();
StringBuilder sb = new StringBuilder();
foreach (var item in all)
{
int order = 1;
var files = item.Select(x =>
{
int lastIndex = x.Url.LastIndexOf('/');
string prefix = x.Url.Substring(0, lastIndex);
string fileName = x.Url.Substring(lastIndex + 1);
return new { Prfx = prefix, FileName = fileName, FileOrder = order++ };
}).OrderBy(x => x.FileOrder);

var keysgroup = files.GroupBy(x => x.Prfx).ToArray();
foreach (var key in keysgroup)
{
var list = files.Where(x => x.Prfx.Equals(key.Key)).ToArray();
sb.Append("[" + list[0].Prfx + "/" + list[0].FileName);
string jsprfx = list[0].Prfx;
for (int i = 1; i < list.Length; i++)
{
sb.Append("," + list[i].FileName);
}
sb.Append("]");
}
}
return sb.ToString();
}
static string[] GetFilePath(string filesrc)
{
List<string> result = new List<string>();
string[] files = filesrc.Split(new char[] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string file in files)
{
string[] srcs = file.Split(new char[] { ',' });
string first = srcs[0];
int index = first.LastIndexOf("/");
string prefx = first.Substring(0, index);
result.Add(first);
if (srcs.Length > 1)
{
srcs = srcs.Where((x, i) => { return i > 0; }).Select(x => prefx + "/" + x).ToArray();
result.AddRange(srcs);
}
}
return result.ToArray();
}
static string GetVersion(ResourceInfo[] items, ResourceType restype)
{
StringBuilder sb = new StringBuilder();
string ext = ".js";
if (restype == ResourceType.StyleSheet)
{
ext = ".css";
}
foreach (ResourceInfo item in items)
{
string filename = item.Url + ext;
string filepath = HttpContext.Current.Server.MapPath(filename);
FileInfo file = new FileInfo(filepath);
sb.Append(file.LastWriteTime.ToString("yyyyMMddHHmmss"));
}
string version = sb.ToString().GetHashCode().ToString();
version = version.Replace("-", string.Empty);

///Read web config

///
return version;
}

}
}


结果如图:



注意Yahoo.Yui.Compressor版本不同,调用方式也不同.

如果是在MVC4项目里,这里可以不用Yahoo.Yui.Compressor来压缩文件,可以用WebGrease.1.1.0\lib\WebGrease.dll中的Minifier类来实现压缩.代码如下:

CodeSettings codeSettings = new CodeSettings

{

EvalTreatment = EvalTreatment.MakeImmediateSafe,

PreserveImportantComments = false

};

content= (new Microsoft.Ajax.Utilities.Minifier()).MinifyJavaScript(content,codeSettings);

--------------------------------------------------------------------

CssSettings setting = new CssSettings() { CommentMode=CssComment.None };

content = (new Microsoft.Ajax.Utilities.Minifier()).MinifyStyleSheet(content,setting);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: