HttpHandler在Asp.net中核心对像之一,我们可以实现IHttpHandler接口来优化Css样式文件. 用一个我们自定义的HttpHandler映射.css的文件.
首先我们最小化Css样式文件尺寸, 然后我们再处理后CSS文件做内存缓存. 缓存依赖物理文件,当文件被修改后,重新加载. 这里我们以Demo为目的,默认
缓存时间2小时. 让我们先来看一下类图是这样的:

ClassDigram1

我们定义一个IFilesCache的接口,是为了实现两种不能缓存方式.一种是有用System.Web.Caching.Cache,别一个是用.net 4.0下System.Runtime.Caching.ObjectCache的内存Cache. 我们定义一个FilesCacheFactory的类根据.net framework当前版来在创建
当前的实例. 当然你可以直接选择其它组件实现缓存. 下面是Handler的代码:

   1:      /// <summary>
   2:      /// MinifyCssHandler 
   3:      /// </summary>
   4:      public class MinifyCssHandler:IHttpHandler
   5:      {
   6:          private IFilesCache cacheContext;
   7:   
   8:          /// <summary>
   9:          /// Initializes a new instance of the <see cref="MinifyCssHandler"/> class.
  10:          /// </summary>
  11:          public MinifyCssHandler()
  12:          {
  13:              cacheContext = FilesCacheFactory.GetInstance();
  14:          }
  15:   
  16:          #region IHttpHandler Members
  17:   
  18:          /// <summary>
  19:          /// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
  20:          /// </summary>
  21:          /// <returns>true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.</returns>
  22:          public bool IsReusable
  23:          {
  24:              get { return true; }
  25:          }
  26:   
  27:          /// <summary>
  28:          /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
  29:          /// </summary>
  30:          /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
  31:          public void ProcessRequest(HttpContext context)
  32:          {
  33:              string fileContent = string.Empty;
  34:              string filePath = context.Request.PhysicalPath;
  35:   
  36:              string cacheKey = string.Concat("css-", filePath);
  37:   
  38:              object cacheValue = cacheContext.GetFromCache(cacheKey);
  39:   
  40:              if (cacheValue == null)
  41:              {
  42:                  fileContent = MinifyFiles(filePath);
  43:                  cacheContext.AddToCache(cacheKey, fileContent, filePath);
  44:              }
  45:              else
  46:              {
  47:                  fileContent = cacheValue as string;
  48:              }
  49:              context.Response.ContentType = "text/css";
  50:              context.Response.Write(fileContent);
  51:          }
  52:   
  53:          #endregion
  54:   
  55:          /// <summary>
  56:          /// MinifyFiles intent to minfiy css files size
  57:          /// </summary>
  58:          /// <param name="filePath">css file path</param>
  59:          /// <returns>css file of content</returns>
  60:          private string MinifyFiles(string filePath)
  61:          {
  62:              string fileContent = File.ReadAllText(filePath);
  63:              fileContent = string.Concat("/* minifyed at ", DateTime.Now, " by Petter Liu */ ", fileContent);
  64:              fileContent = Regex.Replace(fileContent, "\t", string.Empty);
  65:              fileContent = Regex.Replace(fileContent, "\r\n", string.Empty);
  66:              fileContent = Regex.Replace(fileContent, "\r", string.Empty);
  67:              fileContent = Regex.Replace(fileContent, "\n", string.Empty);
  68:              //Replace more than two spaces
  69:              fileContent = Regex.Replace(fileContent, "[ ]{2,}", string.Empty);
  70:              return fileContent;
  71:          }
  72:      }


与Cache相关的类:
 
   1:      /// <summary>
   2:      /// IFilesCache
   3:      /// </summary>
   4:      public interface IFilesCache
   5:      {
   6:          /// <summary>
   7:          /// Add object to cache
   8:          /// </summary>
   9:          /// <param name="key">key</param>
  10:          /// <param name="value">value</param>
  11:          /// <param name="filePath">file path</param>
  12:          void AddToCache(string key, object value, string filePath);
  13:   
  14:          /// <summary>
  15:          /// GetFromCache
  16:          /// </summary>
  17:          /// <param name="key">key</param>
  18:          /// <returns>object</returns>
  19:          object GetFromCache(string key);
  20:      }
  21:   
  22:      /// <summary>
  23:      /// a simple factory create IFilesCache
  24:      /// </summary>
  25:      public class FilesCacheFactory
  26:      {
  27:          /// <summary>
  28:          /// Create IFilesCache instance
  29:          /// </summary>
  30:          /// <remarks>System.Runtime.Caching only runtime at .net framework version 4</remarks>
  31:          /// <returns>IFilesCache</returns>
  32:          public static IFilesCache GetInstance()
  33:          {
  34:              if (Environment.Version.Major==4)
  35:                 return new DotnetRunningCache();
  36:              return new WebContextCache();
  37:          }
  38:   
  39:      }
  40:   
  41:      public class WebContextCache:IFilesCache
  42:      {
  43:         #region IFilesCache Members
  44:          /// <summary>
  45:          /// Add object to cache
  46:          /// </summary>
  47:          /// <param name="key">key</param>
  48:          /// <param name="value">value</param>
  49:          /// <param name="filePath">file path</param>
  50:          public void  AddToCache(string key, object value, string filePath)
  51:          {
  52:              //Cache two hour
  53:              HttpContext.Current.Cache.Insert(key, value,
  54:                                            new CacheDependency(filePath),
  55:                                            DateTime.Now.AddHours(2),
  56:                                            TimeSpan.Zero);
  57:          }
  58:   
  59:          /// <summary>
  60:          /// GetFromCache
  61:          /// </summary>
  62:          /// <param name="key">key</param>
  63:          /// <returns>object</returns>
  64:          public object GetFromCache(string key)
  65:          {
  66:              if (string.IsNullOrEmpty(key))
  67:                  return new ArgumentNullException("cache key should not null");
  68:              return HttpContext.Current.Cache[key];
  69:          }
  70:   
  71:          #endregion
  72:      }
  73:   
  74:      public class DotnetRunningCache:IFilesCache
  75:      {
  76:          #region IFilesCache Members
  77:          /// <summary>
  78:          /// Add object to cache
  79:          /// </summary>
  80:          /// <param name="key">key</param>
  81:          /// <param name="value">value</param>
  82:          /// <param name="filePath">file path</param>
  83:          public void AddToCache(string key, object value, string filePath)
  84:          {
  85:               ObjectCache cache = MemoryCache.Default;
  86:              var cacheValue = new[] { value };
  87:              var cachepolicy = new CacheItemPolicy();
  88:              var filespath=new List<string>(){ filePath};
  89:              cachepolicy.AbsoluteExpiration = DateTimeOffset.Now.AddHours(2);
  90:              cachepolicy.ChangeMonitors.Add(new HostFileChangeMonitor(filespath));
  91:   
  92:              cache.Add(key, cacheValue, cachepolicy);
  93:          }
  94:   
  95:          /// <summary>
  96:          /// GetFromCache
  97:          /// </summary>
  98:          /// <param name="key">key</param>
  99:          /// <returns>object</returns>
 100:          public object GetFromCache(string key)
 101:          {
 102:              if (string.IsNullOrEmpty(key))
 103:                  return new ArgumentNullException("cache key should not null");
 104:   
 105:               ObjectCache cache = MemoryCache.Default;
 106:              var objects= (Object[])cache.Get(key);
 107:              if (objects != null)
 108:                  return objects.FirstOrDefault();
 109:              return null;
 110:          }
 111:   
 112:          #endregion
 113:      }

在Web.config中增加:

   1:          <httpHandlers>
   2:              <add verb="*" path="*.css" validate="false" type="MyWeb.MinifyCssHandler"/>
   3:          </httpHandlers>

Ok,对比一下,正常情况下是这样:

profile_css0

当增加这个优化Css的HttpHandler后, 是这样的:

profile_css1

有注意size从4.2KB变成了3.2KB. 以上我们直是实现比较简单的,你可以优化实现更高效的算法. 或增加扩展.

希望这篇Post对您开发有帮助.


作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog

posted on 2011-09-27 15:05  PetterLiu  阅读(1148)  评论(0编辑  收藏  举报