ASP.NET的运⾏原理与运⾏机制
在Asp4和4.5中,新增了WebPages Framework,编写页⾯代码使⽤了新的Razor语法,代码更加的简洁和符合Web标准,编写⽅式更接近于PHP和以前的Asp,和使⽤WebForms这种模仿Windows Form编程⽅式有了很⼤不同,不再有⼤量控件和控件⽣成的⼤量不够灵活的代码,但是同样可以使⽤Asp提供的⼤量类库和功能,可以说WebPages框架融合了Asp、PHP和Asp的全部优点,⼜可使⽤C#和VB 编程语⾔。⼀看到WebPages框架,我就马上有了深⼊学习的兴趣,因为它和WebForms相⽐⽴刻就会让有完美主义情结的程序员们倾⼼。
但WebPages框架却并没有绑定Razor语法,它可以使⽤第三⽅的视图引擎。WebPages和Razor也并没有和Asp MVC具有必然的联系。在VS2012中默认的⽹站模板⾥⾯多了”Asp⽹站(Razor v2)“,可以根据Razor语法创建WebPage。
WebPages⽹站简介
WebPages⽹站包含多个cshtml或vbhtml页⾯,这些页⾯中使⽤Razor模板语法,整个⽹站的⽂件都在⼀个⽂件夹中,bin⽬录中有各种要⽤到的dll,没有解决⽅案⽂件,解决⽅案⽂件在另外⼀个和⽹站同时创建的项⽬中,其中有packages⽬录以管理WebPages⽹站需要⽤到的包。⼀个普通的cshtml页代码如下:
@{
var db = Database.Open("StarterSite");
var users = db.Query("Select * From UserProfile");
var grid = new WebGrid(users);
}
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
@grid.GetHtml()
</body>
</html>
从中可以看到,这种编写⽅式和PHP、Asp很相似,但WebPages⾝后却是庞⼤的Asp类库。
asp查看源码配置uiWebPages框架相关配置
在WebPages⽹站的fig中并没有什么特殊配置,在 framework 4.0中的fig中相关的配置如下:
<compilation>
<assemblies>
<remove assembly="System.Web.WebPages.Deployment, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add assembly="System.Web.WebPages.Deployment, Version=2.0.0.0, Culture=neutral, PublicKey
Token=31bf3856ad364e35" />
<add assembly="System.Web.WebPages.Deployment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</assemblies>
</compilation>
<httpHandlers>
<add path="*.cshtm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.cshtml" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vbhtm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
<add path="*.vbhtml" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
</httpHandlers>
其中没有相关buildProviders的配置也没有相关httpModules的配置,httpHandlers的配置还将其映射到了HttpForbiddenHandler禁⽌访问。在IIS或IIS Express中的配置中也只有Asp4.0的ISAPI的配置⽽没有相关的httpModule。⽽WebForms在fig中配置有相应的httpHandler和buildProvider。那么WebPages框架是如何运⾏的,其和WebForms在哪⾥产⽣了不同,WebPages框架是如何在Asp框架下实现的,这就需要进⼊WebPages框架进⾏探索。
WebPages框架⾃动运⾏过程
从fig中的System.Web.WebPages.Deployment程序集开始,这个程序集dll有⼀个Asp4.0新增的特性PreApplicationStartMethodAttribute,这个特性配置了⼀个静态⽅法以在程序启动之前⾃动执⾏,特性如下:[assembly: (typeof(), "Start")],查看PreApplicationStartCode类的Start⽅法,其调⽤了StartCore⽅法,StartCore⼜调⽤了LoadWebPages⽅法,其中实现的功能主要是获取所有和WebPages框架相关的dll并得到这些dll上配置的PreApplicationStartMethodAttribute特性对应的启动⽅法并全部执⾏,具有这个特性的dll有System.Web.WebPages、System.Web.WebPages.Razor和WebMatrix.WebData,我们主要关注前两个。
private static void LoadWebPages(Version version)
{
  IEnumerable<Assembly> assemblies = Enumerable.Select<AssemblyName, Assembly>(AssemblyUtils.GetAssembliesForVersion(version),
    new Func<AssemblyName, Assembly>(null, (IntPtr) LoadAssembly));
  foreach (Assembly assembly in assemblies)
  {
BuildManager.AddReferencedAssembly(assembly);
  }
  foreach (MethodInfo info in GetPreStartInitMethodsFromAssemblyCollection(assemblies))
  {
info.Invoke(null, null);
  }
}
在System.Web.WebPages.Razor程序集上的启动⽅法代码如下:
public static class PreApplicationStartCode
{
// Fields
private static bool _startWasCalled;
// Methods
public static void Start()
{
if (!_startWasCalled)
{
_startWasCalled = true;
BuildProvider.RegisterBuildProvider(".cshtml", typeof(RazorBuildProvider));
BuildProvider.RegisterBuildProvider(".vbhtml", typeof(RazorBuildProvider));
}
}
}
其注册了cshtml和vbhtml⽂件对应的BuildProvider为RazorBuildProvider,即编译Razor语法⽂件的提供程序。
在System.Web.WebPages程序集上的启动⽅法代码如下,这些启动类的名字和⽅法是⼀样的
public static class PreApplicationStartCode
{
// Fields
private static bool _startWasCalled;
// Methods
public static void Start()
{
if (!_startWasCalled)
{
_startWasCalled = true;
WebPageHttpHandler.RegisterExtension("cshtml");
WebPageHttpHandler.RegisterExtension("vbhtml");
PageParser.EnableLongStringsAsResources = false;
        //此⾏代码注册了WebPageHttpModule
       DynamicModuleUtility.RegisterModule(typeof(WebPageHttpModule));
ScopeStorage.CurrentProvider = new AspNetRequestScopeStorageProvider();
}
}
}
其中最重要的功能就是⾃动注册了⼀个HttpModule,到此我们就可以知道WebPages页⾯的编译和处理已经有了着落了。接着查看WebPageHttpModule的代码,这个httpmodule注册处理了HttpApplication的PostResolveRequestCache,BeginRequest和EndRequest事件,这些代码会在⽤户请求cshtml和vbhtml页⾯时触发执⾏,在这个过程中WebPageHttpModule还会在WebPages⽹站⾸次启动的时候调⽤System.Web.WebPages.ApplicationStartPage.ExecuteStartPage⽅法,在PostResolveRequestCache事件处理代码中调⽤了WebPageRoute的⽅法,其中创建了处理页⾯的WebPageHttpHandler类。
internal static void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
{
    HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context);
  new WebPageRoute().DoPostResolveRequestCache(context);
}
internal void DoPostResolveRequestCache(HttpContextBase context)
{
if (!this.IsExplicitlyDisabled)
{
string pathValue = context.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + context.Request.PathInfo;
ReadOnlyCollection<string> registeredExtensions = WebPageHttpHandler.GetRegisteredExtensions();
WebPageMatch match = MatchRequest(pathValue, registeredExtensions, this.VirtualPathFactory, context, DisplayModeProvider.Instance);
if (match != null)
{
context.Items[typeof(WebPageMatch)] = match;
string path = "~/" + match.MatchedPath;
        //是否在WebPages⽹站的fig中明确配置了webpages:Enabled
if (!WebPagesDeployment.IsExplicitlyDisabled(path))
{
//创建WebPageHttpHandler
IHttpHandler handler = WebPageHttpHandler.CreateFromVirtualPath(path);
if (handler != null)
{
SessionStateUtil.SetUpSessionState(context, handler);
            //替换fig中配置的HttpForbiddenHandler
context.RemapHandler(handler);
}
}
}
else
{
string extension = PathUtil.GetExtension(pathValue);
foreach (string str4 in registeredExtensions)
{
if (string.Equals("." + str4, extension, StringComparison.OrdinalIgnoreCase))
{
throw new HttpException(0x194, null);
}
}
}
}
}
WebPageRoute还实现了WebPages⽹站页⾯地址更加友好的功能,如不必带cshtml和vbhtml后缀即可访问相应页⾯,可采⽤
filename/category/id之类的地址访问,通过添加xx.Mobile.cshtml即可⾃动实现切换到移动页的功能等。到此HttpHandler创建完毕之后,就开始执⾏页⾯,WebPages页⾯的基类是System.Web.WebPa
ges.WebPage。
如果我们在WebPages⽹站的fig⾥⾯配置了webpages:Enabled为false,那么再次访问cshtml或vbhtml时发现处理它们的是HttpForbiddenHandler。
<appSettings>
<add key="webpages:Enabled" value="false"/>
</appSettings>
⽆法提供此类型的页
⾄此,我们对WebPages框架的相关运⾏原理有了⼀个⼤概的了解。WebPages框架通过Asp4.0提供的PreApplicationStartMethodAttribute特性实现了HttpModule和BuildProvider注册,⽽不是通常的fig配置⽂件,本⽂介绍的过程并不是绝对的,因为这个特性是可以被Asp Runtime⾃动识别和运⾏的,例如只要你引⽤了System.Web.WebPages就会执⾏其上配置的注册WebPageHttpModule的⽅法,其这些程序集上的启动⽅法都有判断机制防⽌重复执⾏。
和Asp MVC中的Razor视图引擎的关系
Razor并没有和MVC紧密耦合,其可以脱离MVC,也可以脱离WebPage框架。System.Web.MVC程序集上也有PreApplicationStartMethodAttribute特性,其中分别直接调⽤了System.Web.WebPages和System.Web.WebPages.Razor中的启动类以注册WebPageHttpModule和RazorBuildProvider,但MVC之中⼜继承了System.Web.Razor中的WebPageRazorHost类实现了⾃⼰特有的MvcWebPageRazorHost,相当于增加了新的功能以和MVC配合。
正如MVC中有多种不同的视图引擎⼀样,WebPages框架也不⼀定要使⽤Razor引擎,我们可以实现⾃⼰的BuildProvider来定义WebPage 语法和解析⽣成.Net程序集。
结语
个⼈认为WebPages框架在⼈们越来越注重Web标准和前端UI的情况下,抛弃了WebForms有些笨重和不透明的编程⽅式,具有极⼤的灵活性同时⼜可以利⽤Asp强⼤的类库,后端的框架模型并没有变,但却让Asp程序员有了和PHP、Asp类似的快速编程体验。受够了WebForms输出代码的臃肿的程序员们,赶快学习WebPages吧:)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。