日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET1.1中预编译ASP.NET页面实现原理浅析[1]自动预编译机制浅析

發布時間:2024/4/15 asp.net 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET1.1中预编译ASP.NET页面实现原理浅析[1]自动预编译机制浅析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

.NET1.1中預編譯ASP.NET頁面實現原理淺析[1]自動預編譯機制淺析

.NET1.1中預編譯ASP.NET頁面實現原理淺析[1]自動預編譯機制淺析


作者:&;nbsp來自:網絡

http://flier_lu.blogone.net?id=1544105?
.net 1.1中預編譯asp.net頁面實現原理淺析

? ? MS在發布ASP.NET時的一大功能特性是,與ASP和PHP等腳本語言不同,ASP.NET實際上是一種編譯型的快速網頁開發環境。這使得ASP.NET在具有開發和修改的簡便性的同時,不會負擔效率方面的損失。實現上ASP.NET與JSP的思路類似,引擎在第一次使用一個頁面之前,會將之編譯成一個類,自動生成Assembly并載入執行。
? ? 而通過《在WinForm程序中嵌入ASP.NET》一文中我們可以了解到,ASP.NET引擎實際上是可以無需通過IIS等Web服務器調用而被使用的,這就使得手工預編譯ASP.NET頁面成為可能。實際上這個需求是普遍存在的,早在ASP時代就層有第三方產品支持將ASP頁面編譯成二進制程序,以提高執行效率和保障代碼安全性,而將伴隨Whidbey發布的ASP.NET 2.0更是直接內置了預編譯ASP.NET頁面的功能。

? ? 實際上網上早就有人討論過在ASP.NET 1.1中模擬預編譯特性的實現方法,例如以下兩篇文章

? ? Pre-Compiling ASP.NET Web Pages
? ? Pre-Compile ASPX pages in .NET 1.1

? ? 其思路基本上都是遍歷所有需要預編譯的頁面文件,然后通過模擬Web頁面請求的方式,觸發ASP.NET引擎的自動預編譯機制。這樣做的好處是完全模擬真實情況,無需了解ASP.NET引擎的實現原理;但同時也會受到諸多限制,如預編譯結果不透明,無法脫離原始ASP.NET頁面文件使用等等,而且無法使我們從原理上理解預編譯特性的實現。

? ? 下面我將分三到四個小節,簡要討論 ASP.NET 自動編譯機制的實現、ASP.NET 頁面文件編譯的實現以及如何在ASP.NET 1.1中實現手動預編譯頁面和相應分發機制。

[1] 自動預編譯機制淺析

? ? 本節我們將詳細分析討論.NET 1.1中,ASP.NET引擎內部實現自動頁面預編譯的原理。

? ? 首先,我們所說的ASP.NET頁面實際上主要分為四類:

? ? 1.Web 應用程序文件? ? Global.asax
? ? 2.Web 頁面文件? ? ? ? *.aspx
? ? 3.用戶自定義控件文件? *.ascx
? ? 4.Web 服務程序文件? ? *.asmx

? ? Web 應用程序文件對于每個Web 應用程序來說是可選唯一的,用來處理ASP.NET應用程序一級的事件,并將被預編譯為一個System.Web.HttpApplication類的子類;
? ? Web 頁面文件是普通的ASP.NET頁面,處理特定頁面的事件,將被預編譯為一個System.Web.UI.Page類的子類;
? ? 用戶自定義控件文件是特殊的ASP.NET頁面,處理控件自身的事件,將被預編譯為一個System.Web.UI.UserControl類的子類;
? ? Web 服務程序文件則是與前三者不太相同的一種特殊頁面文件,暫時不予討論。

? ? 然后,前三種ASP.NET文件的編譯時機也不完全相同。Web 應用程序文件在此 Web 應用程序文件第一次被使用時自動編譯;Web 頁面文件在此Web頁面第一次被使用時自動編譯,實際上是調用 HttpRuntime.ProcessRequest 函數觸發預編譯;用戶自定義控件文件則在其第一次被 Web 頁面使用的時候自動編譯,實際上是調用 Page.LoadControl 函數觸發預編譯。

? ? 在了解了以上這些基本知識后,我們來詳細分析一下自動預編譯的實現機制。

? ? HttpRuntime.ProcessRequest 函數是處理Web頁面請求的調用發起者,偽代碼如下:
?




以下為引用:

public static void HttpRuntime.ProcessRequest(HttpWorkerRequest wr)
{
? // 檢查當前調用者有沒有作為ASP.NET宿主(Host)的權限
? InternalSecurityPermissions.AspNetHostingPermissionLevelMedium.Demand();

? if(wr == null)
? {
? ? throw new ArgumentNullException("custom");
? }

? RequestQueue queue = HttpRuntime._theRuntime._requestQueue;

? if(queue != null)
? {
? ? // 將參數中的Web頁面請求放入請求隊列中
? ? // 并從隊列中使用FIFO策略獲取一個頁面請求
? ? wr = queue.GetRequestToExecute(wr);
? }

? if(wr != null)
? {
? ? // 更新性能計數器
? ? HttpRuntime.CalculateWaitTimeAndUpdatePerfCounter(wr);
? ? // 實際完成頁面請求工作
? ? HttpRuntime.ProcessRequestNow(wr);
? }
}


? ? HttpRuntime.ProcessRequestNow函數則直接調用缺省HttpRuntime實例的ProcessRequestInternal函數完成實際頁面請求工作,偽代碼如下:





以下為引用:

internal static void HttpRuntime.ProcessRequestNow(HttpWorkerRequest wr)
{
? HttpRuntime._theRuntime.ProcessRequestInternal(wr);
}


? ? HttpRuntime.ProcessRequestInternal函數邏輯稍微復雜一些,大致可分為四個部分。

? ? 首先檢查當前HttpRuntime實例是否第一次被調用,如果是第一次調用則通過FirstRequestInit函數初始化;
? ? 接著調用HttpResponse.InitResponseWriter函數初始化頁面請求的返回對象HttpWorkerRequest.Response;
? ? 然后調用HttpApplicationFactory.GetApplicationInstance函數獲取當前 Web 應用程序實例;
? ? 最后使用Web應用程序實例完成實際的頁面請求工作。

? ? 偽代碼如下:





以下為引用:

private void HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr)
{
? // 構造 HTTP 調用上下文對象
? HttpContext ctxt = new HttpContext(wr, 0);

? // 設置發送結束異步回調函數
? wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, ctxt);

? // 更新請求計數器
? Interlocked.Increment(&;amp;(this._activeRequestCount));

? try
? {
? ? // 檢查當前HttpRuntime實例是否第一次被調用
? ? if(this._beforeFirstRequest)
? ? {
? ? ? lock(this)
? ? ? {
? ? ? ? // 使用 Double-Checked 模式 避免冗余鎖定
? ? ? ? if(this._beforeFirstRequest)
? ? ? ? {
? ? ? ? ? this._firstRequestStartTime = DateTime.UtcNow;
? ? ? ? ? this.FirstRequestInit(ctxt); // 初始化當前 HttpRuntime 運行時環境
? ? ? ? ? this._beforeFirstRequest = false;
? ? ? ? }
? ? ? }
? ? }

? ? // 根據配置文件設置,扮演具有較高特權的角色
? ? ctxt.Impersonation.Start(true, false);
? ? try
? ? {
? ? ? // 初始化頁面請求的返回對象
? ? ? ctxt.Response.InitResponseWriter();
? ? }
? ? finally
? ? {
? ? ? ctxt.Impersonation.Stop();
? ? }

? ? // 獲取當前 Web 應用程序實例
? ? IHttpHandler handler = HttpApplicationFactory.GetApplicationInstance(ctxt);

? ? if (handler == null)
? ? {
? ? ? throw new HttpException(HttpRuntime.FormatResourceString("Unable_create_app_object"));
? ? }

? ? // 使用Web應用程序實例完成實際的頁面請求工作
? ? if((handler as IHttpAsyncHandler) != null)
? ? {
? ? ? IHttpAsyncHandler asyncHandler = ((IHttpAsyncHandler) handler);
? ? ? ctxt.AsyncAppHandler = asyncHandler;
? ? ? // 使用異步處理機制
? ? ? asyncHandler.BeginProcessRequest(ctxt, this._handlerCompletionCallback, ctxt);
? ? }
? ? else
? ? {
? ? ? handler.ProcessRequest(ctxt);
? ? ? this.FinishRequest(ctxt.WorkerRequest, ctxt, null);
? ? }
? }
? catch(Exception E)
? {
? ? ctxt.Response.InitResponseWriter();
? ? this.FinishRequest(wr, ctxt, E);
? }
}


? ? HttpRuntime.ProcessRequestInternal函數中,涉及到文件預編譯的有兩部分:一是獲取當前 Web 應用程序實例時,會根據情況自動判斷是否預編譯Web 應用程序文件;二是在完成實際頁面請求時,會在第一次使用某個頁面時觸發預編譯行為。

? ? 首先來看看對 Web 應用程序文件的處理。

? ? HttpRuntime.ProcessRequestInternal函數中調用了HttpApplicationFactory.GetApplicationInstance函數獲取當前 Web 應用程序實例。System.Web.HttpApplicationFactory是一個內部類,用以實現對多個Web應用程序實例的管理和緩存。GetApplicationInstance函數返回的是一個IHttpHandler接口,提供IHttpHandler.ProcessRequest函數用于其后對Web頁面文件的處理。偽代碼如下:





以下為引用:

internal static IHttpHandler HttpApplicationFactory.GetApplicationInstance(HttpContext ctxt)
{
? // 定制應用程序
? if(HttpApplicationFactory._customApplication != null)
? {
? ? return HttpApplicationFactory._customApplication;
? }
? // 調試請求
? if(HttpDebugHandler.IsDebuggingRequest(ctxt))
? {
? ? return new HttpDebugHandler();
? }

? // 判斷是否需要初始化當前 HttpApplicationFactory 實例
? if(!HttpApplicationFactory._theApplicationFactory._inited)
? {
? ? HttpApplicationFactory factory = HttpApplicationFactory._theApplicationFactory;

? ? lock(HttpApplicationFactory._theApplicationFactory);
? ? {
? ? ? // 使用 Double-Checked 模式 避免冗余鎖定
? ? ? if(!HttpApplicationFactory._theApplicationFactory._inited)
? ? ? {
? ? ? ? // 初始化當前 HttpApplicationFactory 實例
? ? ? ? HttpApplicationFactory._theApplicationFactory.Init(ctxt);
? ? ? ? HttpApplicationFactory._theApplicationFactory._inited = true;
? ? ? }
? ? }
? }

? // 獲取 Web 應用程序實例
? return HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(ctxt);
}


? ? 在處理特殊情況和可能的實例初始化之后,調用HttpApplicationFactory.GetNormalApplicationInstance函數完成獲取Web應用程序實例的實際功能,偽代碼如下:





以下為引用:

private HttpApplication HttpApplicationFactory.GetNormalApplicationInstance(HttpContext context)
{
? HttpApplication app = null;

? // 嘗試從已施放的 Web 應用程序實例隊列中獲取
? lock(this._freeList)
? {
? ? if(this._numFreeAppInstances > 0)
? ? {
? ? ? app = (HttpApplication)this._freeList.Pop();
? ? ? this._numFreeAppInstances--;
? ? }
? }

? if(app == null)
? {
? ? // 構造新的 Web 應用程序實例
? app = (HttpApplication)System.Web.HttpRuntime.CreateNonPublicInstance(this._theApplicationType);

? // 初始化 Web 應用程序實例
app.InitInternal(context, this._state, this._eventHandlerMethods);
? }

? return app;
}


? ? 構造新的 Web 應用程序實例的代碼很簡單,實際上就是對Activator.CreateInstance函數的簡單包裝,偽代碼如下:





以下為引用:

internal static object HttpRuntime.CreateNonPublicInstance(Type type, object[] args)
{
? return Activator.CreateInstance(type, BindingFlags.CreateInstance | BindingFlags.Instance |
? ? BindingFlags.NonPublic | BindingFlags.Public, null, args, null);
}

internal static object HttpRuntime.CreateNonPublicInstance(Type type)
{
? return HttpRuntime.CreateNonPublicInstance(type, null);
}


? ? 至此一個 Web 應用程序實例就被完整構造出來,再經過InitInternal函數的初始化,就可以開始實際頁面處理工作了。而HttpApplicationFactory實例的_theApplicationType類型,則是結果預編譯后的Global.asax類。實際的預編譯工作在HttpApplicationFactory.Init函數中完成,偽代碼如下:





以下為引用:

private void HttpApplicationFactory.Init(HttpContext ctxt)
{
if(HttpApplicationFactory._customApplication != null)
return;

? using(HttpContextWrapper wrapper = new HttpContextWrapper(ctxt))
{
? ctxt.Impersonation.Start(true, true);
? try
? {
? ? try
? ? {
? ? ? this._appFilename = HttpApplicationFactory.GetApplicationFile(ctxt);
? this.CompileApplication(ctxt);
? this.SetupChangesMonitor();
? ? }
? ? finally
? ? {
? ? ? ctxt.Impersonation.Stop();
? ? }
? }
? catch(Object)
? {
? }
? this.FireApplicationOnStart(ctxt);
}
}


? ? GetApplicationFile函數返回Web請求物理目錄下的global.asax文件路徑;CompileApplication函數則根據此文件是否存在,判斷是預編譯之并載入編譯后類型,還是直接返回缺省的HttpApplication類型,偽代碼如下:





以下為引用:

internal static string HttpApplicationFactory.GetApplicationFile(HttpContext ctxt)
{
? return Path.Combine(ctxt.Request.PhysicalApplicationPath, "global.asax");
}

private void HttpApplicationFactory.CompileApplication(HttpContext ctxt)
{
? if(FileUtil.FileExists(this._appFilename))
? {
? ? ApplicationFileParser parser;

? ? // 獲取編譯后的 Web 應用程序類型
? ? this._theApplicationType = ApplicationFileParser.GetCompiledApplicationType(this._appFilename, context, out parser);
? ? this._state = new HttpApplicationState(parser1.ApplicationObjects, parser.SessionObjects);
? ? this._fileDependencies = parser.SourceDependencies;
? }
? else
? {
? ? this._theApplicationType = typeof(HttpApplication);
? ? this._state = new HttpApplicationState();
? }
? this.ReflectOnApplicationType();
}


? ? 分析到這里我們可以發現,內部類型System.Web.UI.ApplicationFileParser的GetCompiledApplicationType函數是實際上進行Web應用程序編譯工作的地方。但現在我們暫且打住,等下一節分析編譯過程時再詳細解說。 :)

? ? 然后我們看看對 Web 頁面文件的處理。

? ? 在前面分析HttpRuntime.ProcessRequestInternal函數時我們曾了解到,在獲得了Web應用程序實例后,會使用此實例的IHttpAsyncHandler接口或IHttpHandler接口,完成實際的頁面請求工作。而無論有否Global.asax文件,最終返回的Web應用程序實例都是一個HttpApplication類或其子類的實例,其實現了IHttpAsyncHandler接口,支持異步的Web頁面請求工作。對此接口的處理偽代碼如下:





以下為引用:

private void HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr)
{
? ...

? // 使用Web應用程序實例完成實際的頁面請求工作
? if((handler as IHttpAsyncHandler) != null)
? {
? ? IHttpAsyncHandler asyncHandler = ((IHttpAsyncHandler) handler);
? ? ctxt.AsyncAppHandler = asyncHandler;
? ? // 使用異步處理機制
? ? asyncHandler.BeginProcessRequest(ctxt, this._handlerCompletionCallback, ctxt);
? }
? else
? {
? ? handler.ProcessRequest(ctxt);
? ? this.FinishRequest(ctxt.WorkerRequest, ctxt, null);
? }

? ...
}


? ? HttpRuntime.ProcessRequestInternal函數通過調用HttpApplication.IHttpAsyncHandler.BeginProcessRequest函數開始頁面請求工作。而HttpApplication實際上根本不支持同步形式的IHttpHandler接口,偽代碼如下:





以下為引用:

void HttpApplication.ProcessRequest(System.Web.HttpContext context)
{
? throw new HttpException(HttpRuntime.FormatResourceString("Sync_not_supported"));
}

bool HttpApplication.get_IsReusable()
{
? return true;
}


? ? 而在HttpApplication.IHttpAsyncHandler.BeginProcessRequest函數中,將完成非常復雜的異步調用后臺處理操作,這兒就不多羅嗦了,等有機會寫篇文章專門討論一下ASP.NET中的異步操作再說。而其最終調用還是使用System.Web.UI.PageParser對需要處理的Web頁面進行解析和編譯。

? ? 最后我們看看對用戶自定義控件文件的處理。

? ? Page類的LoadControl函數實際上是在抽象類TemplateControl中實現的,偽代碼如下:





以下為引用:

public Control LoadControl(string virtualPath)
{
? virtualPath = UrlPath.Combine(base.TemplateSourceDirectory, virtualPath);
? Type type = UserControlParser.GetCompiledUserControlType(virtualPath, null, base.Context);
? return this.LoadControl(type1);
}


? ? 實際的用戶自定義控件預編譯操作還是在UserControlParser類中完成的。

? ? 至此,在這一節中我們已經大致了解了ASP.NET自動預編譯的實現原理,以及在什么時候對頁面文件進行預編譯。下一節我們將詳細分析ApplicationFileParser、PageParser和UserControlParser,了解ASP.NET是如何對頁面文件進行預編譯的。

轉載于:https://www.cnblogs.com/danhuoren/archive/2008/08/23/1274761.html

總結

以上是生活随笔為你收集整理的.NET1.1中预编译ASP.NET页面实现原理浅析[1]自动预编译机制浅析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。