zoukankan      html  css  js  c++  java
  • 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);

  • 相关阅读:
    Sql与Asp.Net数据类型对应
    EditPlus 使用技巧集萃
    VB.NET and C# Comparison
    测试后行之CodeSmith模板
    ASP.NET需要改进的地方
    LeetCode: Minimum Path Sum
    LeetCode: Merge k Sorted Lists
    LeetCode: Merge Intervals
    LeetCode: Maximum Subarray
    LeetCode: Median of Two Sorted Arrays
  • 原文地址:https://www.cnblogs.com/majiang/p/2727650.html
Copyright © 2011-2022 走看看