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

在前一篇文章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);


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值