public static readonly string WarmupFilesPath = "~/App_Data/Warmup/" ;
2、 EncodeUrl方法与HttpServerUtility.UrlEncode或HttpUtility.UrlEncode等方法执行结果是不相同 的,它将一个url字符串转换成另一个只包含数字、字母和下滑线的字符串,使之能够作为友好文件名。比如调用 Encodeurl("http://localhost:30320/OrchardLocal/".Trim(‘/‘))将返回字符 串"http_3A_2F_2Flocalhost_3A30320_2Forchardlocal"。
public static string EncodeUrl( string url) {
if (String .IsNullOrWhiteSpace(url)) {
throw new ArgumentException( "url can‘t be empty");
}
var sb = new StringBuilder();
foreach (var c in url.ToLowerInvariant()) {
// only accept alphanumeric chars
if ((c >= ‘a‘ && c <= ‘z‘) || (c >= ‘0‘ && c <= ‘9‘ )) {
sb.Append(c);
}
// otherwise encode them in UTF8
else {
sb.Append( "_");
foreach (var b in Encoding.UTF8.GetBytes(new [] { c })) {
sb.Append(b.ToString( "X"));
}
}
}
return sb.ToString();
}
3、ToUrlString方法一般情况下等效于Request.Url.AbsoluteUri属性的值,源码注释说如果使用了代理请求、负载平衡等可能获取不了真实的绝对Url地址,关于这方面我不太熟悉。
public static string ToUrlString( HttpRequest request) {
return string .Format("{0}://{1}{2}", request.Url.Scheme, request.Headers[ "Host"], request.RawUrl);
}
4、DoBeginRequest方法接收一个HttpApplication型参数,返回一个bool值表示是否已经在该方法内处理了BeginRequest事件。
首 先它通过上面提到的两个方法根据当前请求的绝对Url地址生成一个文件名,然后与WarmupFilesPath字段组合成一个物理文件系统路径。比如对 于请求"http://localhost:30320/OrchardLocal/",生成的物理文件系统路径可能是 @"E:\Orchard.Source.1.4.1.0\src\Orchard.Web\App_Data\Warmup \http_3A_2F_2Flocalhost_3A30320_2Forchardlocal"。DoBeginRequest方法会检查该文件是否 存在。如果存在,则直接Response.WriteFile输出并返回true。如果不存在,则继续检测请求Url对应的物理文件系统路径下是否存在文 件。比如对于请求"http://localhost:30320/OrchardLocal/Default.aspx",将会检测网站目录下是否存在 Default.aspx。如果存在,将不会进入ASP.NET MVC管道处理(当然,MVC也可以在物理文件存在的情况下继续进行路由),直接返回true。这两种情况之外,方法将返回false。该方法会在 WarmupHttpModule类中被使用,如果返回值是false将会把请求放入一个请求队列中——后面将详述。
public static bool DoBeginRequest( HttpApplication httpApplication) {
// use the url as it was requested by the client
// the real url might be different if it has been translated (proxy, load balancing, ...)
var url = ToUrlString(httpApplication.Request);
var virtualFileCopy = WarmupUtility .EncodeUrl(url.Trim(‘/‘));
var localCopy = Path .Combine(HostingEnvironment.MapPath(WarmupFilesPath), virtualFileCopy);
if (File .Exists(localCopy)) {
// result should not be cached, even on proxies
httpApplication.Response.Cache.SetExpires( DateTime.UtcNow.AddDays(-1));
httpApplication.Response.Cache.SetValidUntilExpires( false);
httpApplication.Response.Cache.SetRevalidation( HttpCacheRevalidation.AllCaches);
httpApplication.Response.Cache.SetCacheability( HttpCacheability.NoCache);
httpApplication.Response.Cache.SetNoStore();
httpApplication.Response.WriteFile(localCopy);
httpApplication.Response.End();
return true ;
}
// there is no local copy and the file exists
// serve the static file
if (File .Exists(httpApplication.Request.PhysicalPath)) {
return true ;
}
return false ;
}
二、WarmupHttpModule类和Starter<T>类 这两个类是本文将重点分析的类,这里放在一起来分析。WarmupHttpModule类是一个HttpModule,处理异步BeginRequest事件。WarmupHttpModule已经在~/Web.config进行过注册。Starter<T>类则处理初始化相关事宜。
首先我们来重现两类异常,然后看Orchard中是如何利用这两个类来解决的。
1、模拟初始化异常 通过项目模板新建立一个ASP.NET MVC的项目,在Global.asax.cs文件Application_Start方法开头throw一个异常出来:
throw new Exception();
然后启动调试。在第一次请求发生时,抛出初始化异常: