巧用HttpHandler管理Xslt

用HttpHandler管理XSLT的方法与实践
作者分享用HttpHandler管理XSLT的方法。因公司产品多处用xml+xslt,而其配置不便,作者写此handler解决四个问题,包括自动加Domain、加指定JS、压缩XSLT及控制客户端缓存,还介绍了Xml中连接地址参数含义。

来博客园差不多一年多的时间了,一直都是潜水。感觉自己的知识很单薄,只能努力向各位大牛学习。今天鼓起万分勇气,抱着与大家一起分享的愿望,写了这片文章。还望大家多多拍砖。
好了,废话不多说。进入主题,这篇文章不是介绍xslt的使用方法,关于这类文章,随便在Google,百度一面一搜就是一打。
我想介绍的是,如果用HttpHandler来管理xslt的。有这样的一个想法,主要是来源于公司今年推出的一个产品(选才网)中有好几处都采用了xml+xslt来实现的。
采用xslt的优点我就不重复了,而缺点不知道大家有没有和我一样的感受。不太容易配置。我这里指的的配置,是指,比如说,xslt里面需要引用某个JS,而这个JS的路径根据开发环境和生产环境的不同,路径也会不同。还有就是子系统一多,系统直接访问就可能会牵扯到跨域的问题,这么一来还要在相关xslt文件里面加上Domain的脚本,这样一来,每次发布的时候,都需要来来回回到处配置。我是很讨厌太多配置的,并且还是分布在很多不同的位置。
所以产生了写这么个handler的想法,主要是用来解决这么4个问题:
1. 能够自动为指定Xslt加上Domain。
2. 能够自动为指定Xslt加上指定的一个或多个JS。
3. 能够给Xslt做一下压缩(去空格,去换行)。
4. 能够控制一下客户端缓存。

那么定义Xml中xml-stylesheet连接地址为:xslt.axd?path=~/Common/XSLT/CV/resume.xslt&include=jquery.js&v=1.6.0.27201&age=2592000
path: 就是指定的xslt文件的路径。
include: 需要引用的JS的名称。多个用半角逗号隔开。这里我没用用全路径。考虑到怕JS一多,路径一长,导致url超过限制了。
v: 这个主要是用于强制更新客户端缓存而用的。
age: 这个就是指定客户端缓存的生命期。以秒为单位。加入这个主要是考虑到,每个XSLT根据用途的不同,可能缓存的时间也是不同的。

那么介绍就这么多, 接下来就直接贴代码了。

 

ContractedBlock.gif ExpandedBlockStart.gif Code
  1 public class XsltHandler : IHttpHandler
  2 {
  3     private const string INCLUDE_SCRIPT = "<script type=\"text/javascript\" src=\"{0}\" ></script>";
  4     private const string INCLUDE_SCRIPT_PATH_PRE = "http://localhost/JS/jquery/";
  5     private const string INCLUDE_DOMAIN_SCRIPT = "<script type=\"text/javascript\">document.domain=\"{0}\"</script>";
  6     private static string Domain = String.Empty;
  7 
  8 
  9     public XsltHandler()
 10     {
 11         Domain = GetCurrentDomain();
 12     }
 13 
 14     public void ProcessRequest(HttpContext context) {
 15         string fileName = context.Request.QueryString["path"];
 16         string include = context.Request.QueryString["include"];
 17         string age = context.Request.QueryString["age"];
 18         string xslt;
 19         string includeScripts = string.Empty;
 20         int maxAge = int.MinValue;
 21 
 22         if (!fileName.EndsWith("xslt", StringComparison.OrdinalIgnoreCase))
 23             throw new SecurityException("Invalid Xslt file extension");
 24 
 25         if (!string.IsNullOrEmpty(include)) {
 26             string[] includes = include.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
 27             foreach (string s in includes) {
 28                 if (s.EndsWith(".js", StringComparison.OrdinalIgnoreCase))
 29                     includeScripts += string.Format(INCLUDE_SCRIPT, (INCLUDE_SCRIPT_PATH_PRE + s));
 30             }
 31         }
 32 
 33         if (!string.IsNullOrEmpty(fileName)) {
 34             string path = HttpContext.Current.Server.MapPath(fileName);
 35             //检测缓存中是否已经存在该xslt
 36 
 37             if (context.Cache[context.Request.RawUrl] == null) {
 38                 xslt = RetrieveLocalXslt(path, includeScripts);
 39                 context.Cache.Insert(HttpContext.Current.Request.RawUrl, xslt, new CacheDependency(path));
 40             }
 41             else {
 42                 xslt = (string)context.Cache[context.Request.RawUrl];
 43             }
 44 
 45             SetHeaders(path, context, age);
 46             context.Response.Write(xslt);
 47 
 48             if (true//可做配置项
 49                 Compress(context);
 50         }
 51         else
 52         {
 53             context.Response.StatusCode = (int)HttpStatusCode.NotFound;
 54             context.Response.Status = "404 Bad Request";
 55         }
 56         
 57     }
 58 
 59     /// <summary>
 60     /// 获取当前Domain
 61     /// </summary>
 62     /// <returns>当前请求的Url中的Domain。如:xuancai.com</returns>
 63     private static string GetCurrentDomain()
 64     {
 65         HttpRequest request = HttpContext.Current.Request;
 66         Uri uri = request.Url;
 67         if (uri.HostNameType == UriHostNameType.Dns)
 68         {
 69             // 假定域名符合如下格式:*.domain,如:www.ata.net.cn、www.xuancai.com。
 70             if (Regex.IsMatch(uri.DnsSafeHost, "\\w+(\\.\\w+){2,}", RegexOptions.Singleline))
 71                 return Regex.Replace(uri.DnsSafeHost, Regex.Match(uri.DnsSafeHost, "(\\w+\\.)?", RegexOptions.Singleline).Value, String.Empty);
 72             if (!request.IsLocal)
 73                 return uri.DnsSafeHost;
 74         }
 75         return string.Empty;
 76     }
 77 
 78     /// <summary>
 79     /// 读取本地的xslt文件,并做相关处理。如:去空格,去换行符,加入域,加入需要的js文件等等。
 80     /// </summary>
 81     /// <param name="path">xslt文件路径</param>
 82     /// <param name="include">需要引入的js的字符串 <code><![CDATA[<script type="text/javascript" src="http://localhost/JS/jquery.js"></script]]></code> </param>
 83     /// <returns>经过处理的xslt字符串</returns>
 84     private static string RetrieveLocalXslt(string path, string include) {
 85         try {
 86             string xslt;
 87             using (var reader = new StreamReader(path)) {
 88                 xslt = reader.ReadToEnd();
 89 
 90                 xslt = StripWhitespace(xslt);
 91 
 92                 xslt = xslt.Insert(xslt.LastIndexOf("</body>"), include);
 93 
 94                 if (true && !string.IsNullOrEmpty(Domain)) //可配置是否需要设置Domain。
 95                     xslt = xslt.Insert(xslt.IndexOf("</title>"+ 8string.Format(INCLUDE_DOMAIN_SCRIPT, Domain));
 96             }
 97             return xslt;
 98         }
 99         catch {
100             return string.Empty;
101         }
102     }
103 
104     /// <summary>
105     /// 去掉xslt中的换行符,空格,注释。
106     /// </summary>
107     /// <param name="body">xslt body</param>
108     /// <returns>去空格后的xslt</returns>
109     private static string StripWhitespace(string body) {
110         body = body.Replace("  ", String.Empty);
111         body = body.Replace("\t"string.Empty);
112         body = body.Replace(Environment.NewLine, String.Empty);
113         return body;
114     }
115 
116     /// <summary>
117     /// 设置Response Header
118     /// </summary>
119     /// <param name="path">xslt文件路径</param>
120     /// <param name="context">HttpContext</param>
121     /// <param name="age">需要缓存的时间(单位:秒)</param>
122     private static void SetHeaders(string path, HttpContext context, string age) {
123         context.Response.ContentType = "text/xml";
124         context.Response.Cache.VaryByHeaders["Accept-Encoding"= true;
125 
126         //设置对应的xslt依赖
127         context.Response.AddFileDependency(path);
128         context.Response.Cache.SetETagFromFileDependencies();
129         context.Response.Cache.SetLastModifiedFromFileDependencies();
130         context.Response.Cache.SetSlidingExpiration(true);
131 
132         int maxAge;
133         if (!string.IsNullOrEmpty(age) && int.TryParse(age, out maxAge)) {
134             context.Response.Cache.SetExpires(DateTime.Now.ToUniversalTime().AddSeconds(maxAge));
135             context.Response.Cache.SetMaxAge(TimeSpan.FromSeconds(maxAge));
136             context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);    
137         }
138 
139         string incoming = context.Request.Headers["If-Modified-Since"];
140         //比较客户端缓存中的Modify Time是否与服务器上一样,如果一样则直接输出304。
141         if (incoming != null && DateTime.Parse(incoming).ToShortTimeString() == File.GetLastWriteTime(path).ToShortTimeString()) {
142             context.Response.Clear();
143             context.Response.StatusCode = (int)HttpStatusCode.NotModified;
144             context.Response.SuppressContent = true;
145         }
146     }
147 
148     #region Compression
149 
150     private const string GZIP = "gzip";
151     private const string DEFLATE = "deflate";
152 
153     private static void Compress(HttpContext context) {
154         if (context.Request.UserAgent != null && context.Request.UserAgent.Contains("MSIE 6"))
155             return;
156 
157         if (IsEncodingAccepted(GZIP)) {
158             context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);
159             SetEncoding(GZIP);
160         }
161         else if (IsEncodingAccepted(DEFLATE)) {
162             context.Response.Filter = new DeflateStream(context.Response.Filter, CompressionMode.Compress);
163             SetEncoding(DEFLATE);
164         }
165     }
166 
167     /// <summary>
168     /// 检查是否接受编码
169     /// </summary>
170     private static bool IsEncodingAccepted(string encoding) {
171         return HttpContext.Current.Request.Headers["Accept-encoding"!= null && HttpContext.Current.Request.Headers["Accept-encoding"].Contains(encoding);
172     }
173 
174     /// <summary>
175     /// 设置编码header标签
176     /// </summary>
177     /// <param name="encoding"></param>
178     private static void SetEncoding(string encoding) {
179         HttpContext.Current.Response.AppendHeader("Content-encoding", encoding);
180     }
181 
182     #endregion
183 
184     public bool IsReusable {
185         get { return false; }
186     }
187 }

 

不知道大家是否能够看明白。嘿嘿,第一次写文章,肯定有很多问题。希望大家能够多多指点。也希望能给和我遇到一样问题的同志们有那么一点点帮助。
代码中也有部分注释。如果有朋友没看太明白的,可以提出问题,我尽力解释。

我的MSN是:Wright.Jin@Hotmail.com 欢迎大家一起交流

转载于:https://www.cnblogs.com/wright/archive/2009/04/24/1443028.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值