★33°空間‰


                                 ----★七彩服飾  【最潮拜☆日單精品】【Esprit】【Hotwind】滿150包郵-女裝-流行女裝    www.7color.hb.cn

                                 ----智力比知識重要,素質(zhì)比智力重要,覺悟比素質(zhì)更重要
          posts - 110,comments - 35,trackbacks - 0
          ?文章的題目想了好幾個,比如:“在ASP.NET 2.0中開發(fā)通配符映射應用程序的一些問題”,后來考慮到為了吸引眼球:),并為了好記,選了這個有點俗的題目。
          ???? 本文主要通過分析在ASP.NET 2.0中開發(fā)ASP.NET通配符映射應用程序遇到的一些問題,來說明ASP.NET 2.0中頁面編譯模型的不足之處。文章中如果有不妥之處,歡迎您指出。
          ???? 這里所說的ASP.NET通配符映射應用程序是指在IIS中將所有請求轉發(fā)至ASP.NET 2.0運行時處理(對于IIS 5.0,就是建立.*到aspnet_isapi.dll的映射),在程序中通過實現(xiàn)System.Web.IhttpHandlerFactory接口來處理所有請求,實現(xiàn)System.Web.IhttpHandlerFactory的類就相當于一個前端控制器。典型應用就是.Text及基于.Text開發(fā)的博客園Blog軟件。
          ???? 在ASP.NET 1.1中,實現(xiàn)通配符映射應用程序大家可能比較清楚,主要是兩點:
          ???? 1、?實現(xiàn)System.Web.IhttpHandlerFactory接口,在GetHandler(HttpContext context, string requestType, string url, string path)中根據(jù)請求的url,基于一些規(guī)則,找到實際訪問的頁面文件,然后調(diào)用PageParser.GetCompiledPageInstance對頁面進行編譯并生成相應的實例處理請求。這樣做的好處是:你可以使用任意的url地址,不必關心是否存在對應的頁面文件,而且可以方便地控制對Web服務器上資源的訪問。
          ???? 2、?在web.config中加上:
          < httpHandlers >
          ????
          < add? path ="*" ?verb ="*" ?type ="Dottext.Common.UrlManager.UrlReWriteHandlerFactory,Dottext.Common" ?validate ="false" ? />

          </ httpHandlers >

          ???? ASP.NET 2.0中新的頁面編譯模型給實現(xiàn)通配符映射應用程序帶來意想不到的問題,下面我以博客園Blog軟件為例與大家一些探討這些問題。
          ???? 在博客園Blog軟件中,實現(xiàn)IhttpHandlerFactory接口的是Dottext.Common.UrlManager. UrlReWriteHandlerFactory,不改變在ASP.NET 1.1中實現(xiàn)的UrlReWriteHandlerFactory代碼,直接在ASP.NET 2.0中編譯并運行,當程序運行在IIS根目錄下,就會在執(zhí)行PageParser.GetCompiledPageInstance時出現(xiàn)“Object reference not set to an instance of an object”異常(運行在虛擬目錄中不會出現(xiàn)這個問題)。這個問題是ASP.NET 2.0中的一個小Bug,之前我寫的
          PageParser.GetCompiledPageInstance中的一個Bug及解決方法 對這個問題進行了一些分析,這個問題可以通過在PageParser.GetCompiledPageInstance之前調(diào)用context.RewritePath("~/default.aspx")解決。
          ????? 接著進行訪問個人Blog主頁的測試,比如:
          http://www.cnblogs.com/dudu ,訪問時出現(xiàn)錯誤:

          “There?is?no?build?provider?registered?for?the?extension?''.?You?can?register?one?in?the? < compilation >< buildProviders > ?section?in?machine.config?or?web.config.?Make?sure?is?has?a?BuildProviderAppliesToAttribute?attribute?which?includes?the?value?'Web'?or?'All'.”

          ???? 在ASP.NET 2.0中,當我們第一次訪問一個頁面時,必不少的兩個過程是:1、頁面編譯 2、創(chuàng)建編譯后的頁面代碼的實例。頁面編譯是根據(jù)所訪問的url地址中的擴展名找到匹配的Build Provider對頁面進行編譯。這里出現(xiàn)的問題是由于ASP.NET 2.0運行時沒找到相應的Build Provider,對 http://www.cnblogs.com/dudu 這樣地址,由于使用了通配符映射,在ASP.NET 2.0運行時處理時,得到的擴展名是空(如果沒有使用通配符映射,IIS會自動將地址改為: http://www.cnblogs.com/dudu/default.aspx )。ASP.NET 2.0在這里的設計不足之處是沒有考慮這種情況,無法通過在web.config中進行相應的配置來解決這個問題。如果能提供下面的配置,這個問題就可以輕松解決:

          < buildProviders? >
          ????????
          < add?? extension =".*" ?type ="System.Web.Compilation.PageBuildProvider" />

          </ buildProviders >

          ???? 對于這個問題,我的解決方法是在PageParser.GetCompiledPageInstance之前對url進行處理,在url中加上缺省文件,比如:default.aspx。如果你想使用其他的擴展名,比如:.html,需要在web.config中加上:

          < buildProviders? >
          ????????
          < add?? extension =".html" ?type ="System.Web.Compilation.PageBuildProvider" />

          </ buildProviders >

          ???? 這里還有一個小bug,在上面的錯誤信息“Make sure is has a BuildProvider AppliesToAttribute attribute which includes the value 'Web' or 'All'.”提示需要設置AppliesToAttribute屬性,實際上web.config中并不支持這樣的屬性,可能是正式版之前的ASP.NET 2.0支持過這個屬性,后來去掉后,錯誤提示信息并沒有修改。
          ???? 解決了上面的兩個問題,原以為通配符映射應用程序可以在ASP.NET 2.0中正常運行了,我在本機上測試博客園的程序,頁面能正常訪問。可是今天凌晨在服務器進上將網(wǎng)站升級到ASP.NET 2.0之后,發(fā)現(xiàn)ASP.NET運行時在頻繁地編譯頁面,CPU占用一直100%,編譯了一個多小時還在編譯,而且編譯似乎與訪問量有關,訪問少的站點頁面還能打開,博客園主站由于訪問量大,幾乎無法訪問。問題出在哪?于是我從PageParser.GetCompiledPageInstance的源代碼尋找線索,在BuildManager.GetCacheKeyFromVirtualPath中發(fā)現(xiàn)可疑之處,BuildManager是根據(jù)所請求的虛擬路徑創(chuàng)建緩存鍵,然后根據(jù)這個鍵查找或創(chuàng)建頁面編譯后的緩存對象。當對一個頁面發(fā)出請求時,BuildManager會檢查緩存,先從內(nèi)存中檢查,如果內(nèi)存中沒有就從緩存文件夾(Temporary ASP.NET Files)中查找,如果找到,就直接創(chuàng)建該類型的實例,不進行動態(tài)編譯。如果沒找到,就進行頁面編譯工作,而且查找的依據(jù)就是根據(jù)虛擬路徑創(chuàng)建的緩存鍵。對于通常的頁面訪問方式,這樣處理不會引起問題。但對于通配符映射的情況,就會帶來問題。因為通配符映射時,常見情況是不同的url地址訪問的卻是同一個頁面文件。比如博客園中每篇文章地址不同,但訪問的卻是同樣的頁面代碼,如果按照目前ASP.NET 2.0中的頁面編譯模型,每篇文章第一次訪問都要進行編譯,如果博客園中的幾十萬篇文章被訪問,就要進行幾十萬編譯,難怪今天博客園網(wǎng)站升級至ASP.NET 2.0之后,服務器一直忙于編譯。
          經(jīng)過測試情況果然這樣,當然訪問地址:
          http://www.cnblogs.com/dudu/archive/2006/03/07/345107.html 時會在Temporary ASP.NET Files中文件夾編譯生成類ASP.dudu_archive_2006_03_07_345107_html,而訪問其他文章地時,也根據(jù)文章地址生成另外一個類(2006年3月12日修改:對于這個問題,通過傳給PageParser.GetCompiledPageInstance一個真實的虛擬地址就能解決問題,比如在博客園程序中,對于上面的地址,改為這樣的代碼就行了:GetCompiledPageInstance(app+"~/default.aspx", pagepath, context))。 這樣編譯效率實在太低了!為什么要根據(jù)虛擬路徑創(chuàng)建緩鍵,設計者設計時根本沒考慮到通配符映射的問題,真是糟糕的設計!如果按照ASP.NET 1.1那樣根據(jù)實際訪問的頁面文件名創(chuàng)建緩存鍵,就可以輕松地避免這個問題。ASP.NET 2.0新的頁面編譯模型在這里似乎是一個敗筆。更糟糕的是連讓開發(fā)人員彌補這個Bug的機會都沒有,System.Web.Compilation.BuildManager中沒有提供一個讓開發(fā)人員自己設置緩存鍵的方法或屬性。(注:創(chuàng)建緩存鍵的方法是BuildManager. GetCacheKeyFromVirtualPath(VirtualPath virtualPath, out bool keyFromVPP))。更糟糕的是,System.Web.Compilation中的很多類都是internal,很多類的方法是灰色(Reflector用灰色顯示internal static或private,顏色用的不錯,讓人看了就灰心),想自己調(diào)用相應方法進行頁面編譯幾乎是不可能(用反射的方法不知能否調(diào)用,還沒試過,即使能調(diào)用,也要考慮性能上的損失)。難道要自己寫System.Web.Compilation中那些類去處理頁面編譯?我寧愿選擇ASP.NET 1.1,然后等ASP.NET 2.0 SP1,SP1解決不了,等SP2......希望不要等到ASP.NET 3.0。
          ????? 也許你想到了在GetHandler(HttpContext context, string requestType, string url, string path)中調(diào)用System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath來編譯并創(chuàng)建頁面的實例。這個方法我也嘗試過,答案是不行,還不如PageParser.GetCompiledPageInstance,至少后者能讓程序運行起來。使用BuildManager.CreateInstanceFromVirtualPath時,當訪問的地址中不帶擴展名時就會出現(xiàn)“The resource cannot be found”錯誤,原因是在GetVPathBuildResultInternal(VirtualPath virtualPath, bool noBuild, bool allowCrossApp, bool allowBuildInPrecompile)中調(diào)用了Util.CheckVirtualFileExists(virtualPath)對虛擬路徑進行檢查,檢查時將虛擬路徑轉換為物理路徑,檢查當前請求的頁面文件是否存在,對于通配符映射應用程序,很多地址是實際上不存在的,所以就出現(xiàn)“The resource cannot be found”錯誤。而PageParser.GetCompiledPageInstance中通過調(diào)用HostingEnvironment.AddVirtualPathToFileMapping避免了這個問題。而這個方法被
          Internal保護,在代碼中也無法調(diào)用。
          ????? 我覺得問題的核心是ASP.NET 2.0設計者在設計時沒有考慮通配符映射這樣的情況。是忽略還是另有考慮,就不得而知了。但ASP.NET 1.1能正確處理這個問題,而ASP.NET 2.0卻處理不了,這里很不應該的。使用通配符映射的Web應用程序用戶只能望ASP.NET 2.0心嘆。最近花了很大精力想把博客園的程序遷移到ASP.NET 2.0,而結果卻是無法遷移到ASP.NET 2.0,令人失望! 只能寄希望微軟推出相應的補丁。
          ???? 還好,使用通配符映射的Web應用程序不是很多,這個問題影響不是很大。

          posted on 2006-09-20 13:36 圣域飛俠 閱讀(199) 評論(0)  編輯  收藏 所屬分類: ASP.NET
          主站蜘蛛池模板: 张家口市| 龙泉市| 炎陵县| 商水县| 阿克陶县| 新巴尔虎左旗| 土默特左旗| 温州市| 扎兰屯市| 冀州市| 司法| 霍城县| 罗定市| 泰兴市| 巩义市| 邢台县| 靖西县| 汾阳市| 清新县| 仙居县| 宣汉县| 芮城县| 尼木县| 新绛县| 靖江市| 绿春县| 报价| 东海县| 同仁县| 宁夏| 闸北区| 安乡县| 江川县| 加查县| 威宁| 西青区| 门头沟区| 唐海县| 咸阳市| 宜宾县| 公主岭市|