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

上次写了两篇有关js的合并压缩如

web优化之-js动态合并 动态压缩 去掉js重复引用 js缓存 js延迟加载

web优化之-asp.net js延迟加载 js动态合并 js动态压缩

看了一下的访问两比较大,现在js和css的合并压缩整理一下。

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

代码如下:

 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;
            }
        }
    }


同样我们还需要写一个扩展方法:

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。欢迎大家拍砖。

posted on 2012-08-30 11:41  dz45693  阅读(1253)  评论(0编辑  收藏  举报

导航