你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:技术专栏 / Web开发
web优化之-Asp.net MVC js、css动态合并 动态压缩
 

上次写了两篇有关js的合并压缩如
web优化之-mvc js动态合并 动态压缩 去掉js重复引用 js缓存 js延迟加载
web优化之-asp.net js延迟加载 js动态合并 js动态压缩
看了一下的访问两比较大,现在js和css的合并压缩整理一下。

首先还是需要一个handler来处理文件的合并、压缩、缓存,.js和css的压缩我们采用的是Yahoo.Yui.Compressor,所以需要引用Yahoo.Yui.Compressor.dll文件

代码如下:


[csharp] view plaincopyprint?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; 
           if (!allkeys.Contains("href") || !allkeys.Contains("type") || !allkeys.Contains("compress")) 
           { 
               response.Write("请求格式不正确,正确格式是type=....&href=....&compress=..."); 
               response.Write("type只能是js或则css,compress只能是true或则false,href则是请求的文件,多个文件已逗号分隔"); 
           } 
           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) 
               { 
                   #region 合并压缩文件  
                   /*合并文件*/ 
                   string href = context.Request.QueryString["href"].Trim(); 
                   string content = string.Empty; 
                   string[] files = href.Split(new string[] { ",", "," }, StringSplitOptions.RemoveEmptyEntries); 
                   StringBuilder sb = new StringBuilder(); 
                   foreach (string fileName in files) 
                   { 
                       string filePath = context.Server.MapPath(fileName); 
                       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); 
                       } 
                       else if (fileType.Equals("css")) 
                       { 
                           content = CssCompressor.Compress(content); 
                       } 
                   } 
                   /*压缩文件*/
                   #endregion  
                   cacheItem = new CacheItem() { Content = content, Expires = DateTime.Now.AddHours(1) }; 
                   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); 
               } 
           }  //合并文件结束  
       } 
       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 bool IsReusable 
       { 
           get 
           { 
               return false; 
           } 
       } 
   } 

 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;
            if (!allkeys.Contains("href") || !allkeys.Contains("type") || !allkeys.Contains("compress"))
            {
                response.Write("请求格式不正确,正确格式是type=....&href=....&compress=...");
                response.Write("type只能是js或则css,compress只能是true或则false,href则是请求的文件,多个文件已逗号分隔");
            }
            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)
                {
                    #region 合并压缩文件
                    /*合并文件*/
                    string href = context.Request.QueryString["href"].Trim();
                    string content = string.Empty;
                    string[] files = href.Split(new string[] { ",", "," }, StringSplitOptions.RemoveEmptyEntries);
                    StringBuilder sb = new StringBuilder();
                    foreach (string fileName in files)
                    {
                        string filePath = context.Server.MapPath(fileName);
                        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);
                        }
                        else if (fileType.Equals("css"))
                        {
                            content = CssCompressor.Compress(content);
                        }
                    }
                    /*压缩文件*/
                    #endregion
                    cacheItem = new CacheItem() { Content = content, Expires = DateTime.Now.AddHours(1) };
                    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);
                }
            }  //合并文件结束
        }
        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 bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
同样我们还需要写一个扩展方法:


[csharp] view plaincopyprint?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; 
 
    public static class CombineJSCss 
    { 
        class AppendInfo 
        { 
            public string Url { set; get; } 
            public int Group { set; get; } 
            public int Order { set; get; } 
        } 
        const string jsAppendFileKey = "JSAppendFileKey"; 
        const string jsRemoveFileKey = "JSRemoveFileKey"; 
        const string jsRemoveGroupKey = "JSRemoveGroupKey"; 
        const string cssAppendFileKey = "CSSAppendFileKey"; 
        const string cssRemoveFileKey = "CSSRemoveFileKey"; 
        const string cssRemoveGroupKey = "CSSRemoveGroupKey"; 
 
        #region private Method  
 
        private static void AppendFiles(HtmlHelper htmlHelper, string url, int group, int order, string appendFileKey) 
        { 
            Dictionary<string, AppendInfo> files = null; 
            url = url.ToLower().Trim(); 
            if (string.IsNullOrEmpty(url)) return; 
            IDictionary Items = htmlHelper.ViewContext.HttpContext.Items; 
            if (Items.Contains(appendFileKey)) 
            { 
                files = Items[appendFileKey] as Dictionary<string, AppendInfo>; 
            } 
            else 
            { 
                files = new Dictionary<string, AppendInfo>(); 
                Items.Add(appendFileKey, files); 
            } 
            if (files.Keys.Contains(url)) 
            { 
                files[url].Group = group; 
                files[url].Order = order; 
            } 
            else 
            { 
                files.Add(url, new AppendInfo() { Url = url, Group = group, Order = order }); 
            } 
 
            Items[appendFileKey] = files; 
        } 
 
        private static void RemoveFiles(HtmlHelper htmlHelper, string url, int? group, string removeFilekey, string removeGroupKey) 
        { 
            
            IDictionary Items = htmlHelper.ViewContext.HttpContext.Items; 
            if (!string.IsNullOrEmpty(url)) 
            { 
                url = url.Trim().ToLower(); 
                List<string> removeFileKeys = null; 
                if (Items.Contains(removeFilekey)) 
                { 
                    removeFileKeys = Items[removeFilekey] as List<string>; 
                } 
                else 
                { 
                    removeFileKeys = new List<string>(); 
                    Items.Add(removeFilekey, removeFileKeys); 
                } 
                if (!removeFileKeys.Contains(url)) 
                { 
 
                    removeFileKeys.Add(url); 
                } 
                /*按照js的地址移除*/ 
            } 
            if (group.HasValue) 
            { 
                List<int> removeGroupKeys = null; 
                if (Items.Contains(removeGroupKey)) 
                { 
                    removeGroupKeys = Items[removeGroupKey] as List<int>; 
                } 
                else 
                { 
                    removeGroupKeys = new List<int>(); 
                    Items.Add(removeGroupKey, removeGroupKeys); 
                } 
                if (!removeGroupKeys.Contains(group.Value)) 
                { 
                    removeGroupKeys.Add(group.Value); 
                } 
                /*按照js的group移除*/ 
            } 
        } 
 
        private static MvcHtmlString RenderFiles(HtmlHelper htmlHelper, string appendFileKey, string removeFilekey, string removeGroupKey, Func<string, string> fun) 
        { 
            Dictionary<string, AppendInfo> appendfiles = null; 
            StringBuilder content = new StringBuilder(); 
            IDictionary Items = htmlHelper.ViewContext.HttpContext.Items; 
            if (Items.Contains(appendFileKey)) 
            { 
                appendfiles = Items[appendFileKey] as Dictionary<string, AppendInfo>; 
                List<string> removeFileKeys = new List<string>(); 
                if (Items.Contains(removeFilekey)) 
                { 
                    removeFileKeys = Items[removeFilekey] as List<string>; 
                } 
                List<int> removeGroupKeys = new List<int>(); 
                if (Items.Contains(removeGroupKey)) 
                { 
                    removeGroupKeys = Items[removeGroupKey] as List<int>; 
                } 
                List<AppendInfo> files = appendfiles.Select(x => x.Value) 
                    .Where(x => !removeFileKeys.Contains(x.Url) && !removeGroupKeys.Contains(x.Group)) 
                    .ToList<AppendInfo>(); 
 
                IEnumerable<IGrouping<int, AppendInfo>> groupFiles = files.OrderBy(x => x.Group).GroupBy(x => x.Group); 
                foreach (IGrouping<int, AppendInfo> item in groupFiles) 
                { 
                    string filepath = item.OrderBy(x => x.Order).Select(x => x.Url).ToArray().Aggregate((x, y) => x + "," + y); 
                    content.Append(fun(filepath)); 
                } 
 
 
            }//end if  
            return new MvcHtmlString(content.ToString()); 
        } 
        #endregion 
 
        #region Public method  
        public static void AppendJsFille(this HtmlHelper htmlHelper, string url, int group = 1, int order = 1) 
        { 
            AppendFiles(htmlHelper, url, group, order, jsAppendFileKey); 
        } 
 
        public static void RemoveJsFille(this HtmlHelper htmlHelper, string url, int? group=null) 
        { 
            RemoveFiles(htmlHelper, url, group, jsRemoveFileKey, jsRemoveGroupKey); 
        } 
 
        public static MvcHtmlString RenderJsFille(this HtmlHelper htmlHelper) 
        { 
            return RenderFiles(htmlHelper, jsAppendFileKey, jsRemoveFileKey, jsRemoveGroupKey, x => 
            { 
                string jsformat = "<script type=\"text/javascript\" src=\"/CombineFiles.ashx?type=js&compress=true&href={0}\"></script>"; 
                return string.Format(jsformat, x); 
            }); 
        } 
 
        public static void AppendCssFille(this HtmlHelper htmlHelper, string url, int group = 1, int order = 1) 
        { 
            AppendFiles(htmlHelper, url, group, order, cssAppendFileKey); 
        } 
 
        public static void RemoveCssFille(this HtmlHelper htmlHelper, string url, int? group=null) 
        { 
            RemoveFiles(htmlHelper, url, group, cssRemoveFileKey, cssRemoveGroupKey); 
        } 
 
        public static MvcHtmlString RenderCssFille(this HtmlHelper htmlHelper) 
        { 
            return RenderFiles(htmlHelper, cssAppendFileKey, cssRemoveFileKey, cssRemoveGroupKey, x => 
            { 
                string cssformat = "<link charset=\"utf-8\" rel=\"stylesheet\" type=\"text/css\" href=\"/CombineFiles.ashx?type=js&compress=false&href={0}\">"; 
                return string.Format(cssformat, x); 
            }); 
        } 
        #endregion  
 
    } 

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;

    public static class CombineJSCss
    {
        class AppendInfo
        {
            public string Url { set; get; }
            public int Group { set; get; }
            public int Order { set; get; }
        }
        const string jsAppendFileKey = "JSAppendFileKey";
        const string jsRemoveFileKey = "JSRemoveFileKey";
        const string jsRemoveGroupKey = "JSRemoveGroupKey";
        const string cssAppendFileKey = "CSSAppendFileKey";
        const string cssRemoveFileKey = "CSSRemoveFileKey";
        const string cssRemoveGroupKey = "CSSRemoveGroupKey";

        #region private Method

        private static void AppendFiles(HtmlHelper htmlHelper, string url, int group, int order, string appendFileKey)
        {
            Dictionary<string, AppendInfo> files = null;
            url = url.ToLower().Trim();
            if (string.IsNullOrEmpty(url)) return;
            IDictionary Items = htmlHelper.ViewContext.HttpContext.Items;
            if (Items.Contains(appendFileKey))
            {
                files = Items[appendFileKey] as Dictionary<string, AppendInfo>;
            }
            else
            {
                files = new Dictionary<string, AppendInfo>();
                Items.Add(appendFileKey, files);
            }
            if (files.Keys.Contains(url))
            {
                files[url].Group = group;
                files[url].Order = order;
            }
            else
            {
                files.Add(url, new AppendInfo() { Url = url, Group = group, Order = order });
            }

            Items[appendFileKey] = files;
        }

        private static void RemoveFiles(HtmlHelper htmlHelper, string url, int? group, string removeFilekey, string removeGroupKey)
        {
          
            IDictionary Items = htmlHelper.ViewContext.HttpContext.Items;
            if (!string.IsNullOrEmpty(url))
            {
                url = url.Trim().ToLower();
                List<string> removeFileKeys = null;
                if (Items.Contains(removeFilekey))
                {
                    removeFileKeys = Items[removeFilekey] as List<string>;
                }
                else
                {
                    removeFileKeys = new List<string>();
                    Items.Add(removeFilekey, removeFileKeys);
                }
                if (!removeFileKeys.Contains(url))
                {

                    removeFileKeys.Add(url);
                }
                /*按照js的地址移除*/
            }
            if (group.HasValue)
            {
                List<int> removeGroupKeys = null;
                if (Items.Contains(removeGroupKey))
                {
                    removeGroupKeys = Items[removeGroupKey] as List<int>;
                }
                else
                {
                    removeGroupKeys = new List<int>();
                    Items.Add(removeGroupKey, removeGroupKeys);
                }
                if (!removeGroupKeys.Contains(group.Value))
                {
                    removeGroupKeys.Add(group.Value);
                }
                /*按照js的group移除*/
            }
        }

        private static MvcHtmlString RenderFiles(HtmlHelper htmlHelper, string appendFileKey, string removeFilekey, string removeGroupKey, Func<string, string> fun)
        {
            Dictionary<string, AppendInfo> appendfiles = null;
            StringBuilder content = new StringBuilder();
            IDictionary Items = htmlHelper.ViewContext.HttpContext.Items;
            if (Items.Contains(appendFileKey))
            {
                appendfiles = Items[appendFileKey] as Dictionary<string, AppendInfo>;
                List<string> removeFileKeys = new List<string>();
                if (Items.Contains(removeFilekey))
                {
                    removeFileKeys = Items[removeFilekey] as List<string>;
                }
                List<int> removeGroupKeys = new List<int>();
                if (Items.Contains(removeGroupKey))
                {
                    removeGroupKeys = Items[removeGroupKey] as List<int>;
                }
                List<AppendInfo> files = appendfiles.Select(x => x.Value)
                    .Where(x => !removeFileKeys.Contains(x.Url) && !removeGroupKeys.Contains(x.Group))
                    .ToList<AppendInfo>();

                IEnumerable<IGrouping<int, AppendInfo>> groupFiles = files.OrderBy(x => x.Group).GroupBy(x => x.Group);
                foreach (IGrouping<int, AppendInfo> item in groupFiles)
                {
                    string filepath = item.OrderBy(x => x.Order).Select(x => x.Url).ToArray().Aggregate((x, y) => x + "," + y);
                    content.Append(fun(filepath));
                }


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

        #region Public method
        public static void AppendJsFille(this HtmlHelper htmlHelper, string url, int group = 1, int order = 1)
        {
            AppendFiles(htmlHelper, url, group, order, jsAppendFileKey);
        }

        public static void RemoveJsFille(this HtmlHelper htmlHelper, string url, int? group=null)
        {
            RemoveFiles(htmlHelper, url, group, jsRemoveFileKey, jsRemoveGroupKey);
        }

        public static MvcHtmlString RenderJsFille(this HtmlHelper htmlHelper)
        {
            return RenderFiles(htmlHelper, jsAppendFileKey, jsRemoveFileKey, jsRemoveGroupKey, x =>
            {
                string jsformat = "<script type=\"text/javascript\" src=\"/CombineFiles.ashx?type=js&compress=true&href={0}\"></script>";
                return string.Format(jsformat, x);
            });
        }

        public static void AppendCssFille(this HtmlHelper htmlHelper, string url, int group = 1, int order = 1)
        {
            AppendFiles(htmlHelper, url, group, order, cssAppendFileKey);
        }

        public static void RemoveCssFille(this HtmlHelper htmlHelper, string url, int? group=null)
        {
            RemoveFiles(htmlHelper, url, group, cssRemoveFileKey, cssRemoveGroupKey);
        }

        public static MvcHtmlString RenderCssFille(this HtmlHelper htmlHelper)
        {
            return RenderFiles(htmlHelper, cssAppendFileKey, cssRemoveFileKey, cssRemoveGroupKey, x =>
            {
                string cssformat = "<link charset=\"utf-8\" rel=\"stylesheet\" type=\"text/css\" href=\"/CombineFiles.ashx?type=js&compress=false&href={0}\">";
                return string.Format(cssformat, x);
            });
        }
        #endregion

    }
}来看看我们的调用吧,先看看3个view :Index.cshtml、Demo.cshtml、Test.cshtml

 \
 


那么再来看看_Layout.cshtml吧:

 \

运行的结果如图,请注意js和css各文件的顺序:

 \


再来确认缓存吧

 \


本例代码简单,可能还有一些bug。欢迎大家拍砖。

  推荐精品文章

·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 
·2023年7月目录
·2023年6月目录 
·2023年5月目录
·2023年4月目录 
·2023年3月目录 
·2023年2月目录 
·2023年1月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089