Asp.net 4.0,首次請求目錄下的文件時響應很慢


1. 問題起因
2. 嘗試過的處理思路
3. 解決方法

 

1. 問題起因

    一個從VS2003(.Net Framework 1.1)升級到.net framework 4.0的項目,每次編譯或者部署到服務器上后,首次請求任何一個目錄下的默認頁面時,都要耗時3~5秒;而以前使用.net framework 1.1的時候,沒有這個問題。

我在頁面上開啟Trace="true"來跟蹤,發現頁面的處理時間並不久(IIS重啟,首次打開頁面時截獲的信息):

  但是IIS日志中,顯示首次請求頁面的耗時接近4.635秒。后續連續刷新頁面,處理時間比較正常。。

雖然耗時比較久,但頁面能夠打開;然后我重啟IIS,再次打開站點,用VS附加W3WP.exe來進行調試,再次打開這個頁面的時候,發現拋出異常了:發生了 System.ArgumentException, Message=已存在具有相同鍵的條目。

   1: 發生了 System.ArgumentException
   2:   Message=已存在具有相同鍵的條目。
   3:   Source=System
   4:   StackTrace:
   5:        在 System.Collections.Specialized.ListDictionary.Add(Object key, Object value)
   6:   InnerException: 
   7:     System.dll!System.Collections.Specialized.ListDictionary.Add(object key, object value) + 0x134 字節    
   8:      System.Web.dll!System.Web.UI.ParsedAttributeCollection.AddFilteredAttribute(string filter, string name, string value) + 0xba 字節    
   9:      System.Web.dll!System.Web.UI.TemplateParser.ProcessAttributes(System.Text.RegularExpressions.Match match, out System.Web.UI.ParsedAttributeCollection attribs = {System.Web.UI.ParsedAttributeCollection}, bool fDirective = false, out string duplicateAttribute = null) + 0x221 字節    
  10:      System.Web.dll!System.Web.UI.TemplateParser.ProcessBeginTag(System.Text.RegularExpressions.Match match = {System.Text.RegularExpressions.Match}, string inputText) + 0x68 字節    
  11:      System.Web.dll!System.Web.UI.TemplateParser.ParseStringInternal(string text, System.Text.Encoding fileEncoding) + 0x3d0 字節    
  12:      System.Web.dll!System.Web.UI.TemplateParser.ParseString(string text, System.Web.VirtualPath virtualPath, System.Text.Encoding fileEncoding) + 0x6f 字節    
  13:      System.Web.dll!System.Web.UI.TemplateParser.ParseFile(string physicalPath, System.Web.VirtualPath virtualPath) + 0x115 字節    
  14:      System.Web.dll!System.Web.UI.TemplateParser.ParseInternal() + 0x57 字節    
  15:      System.Web.dll!System.Web.UI.TemplateParser.Parse() + 0x64 字節    
  16:      System.Web.dll!System.Web.Compilation.BaseTemplateBuildProvider.CodeCompilerType.get() + 0x6f 字節    
  17:      System.Web.dll!System.Web.Compilation.BuildProvider.GetCompilerTypeFromBuildProvider(System.Web.Compilation.BuildProvider buildProvider) + 0x42 字節    
  18:      System.Web.dll!System.Web.Compilation.WebDirectoryBatchCompiler.CompileNonDependentBuildProviders(System.Collections.ICollection buildProviders) + 0xca 字節    
  19:      System.Web.dll!System.Web.Compilation.WebDirectoryBatchCompiler.Process() + 0x5d 字節    
  20:      System.Web.dll!System.Web.Compilation.BuildManager.BatchCompileWebDirectoryInternal(System.Web.Hosting.VirtualDirectory vdir, bool ignoreErrors) + 0x48 字節    
  21:      System.Web.dll!System.Web.Compilation.BuildManager.BatchCompileWebDirectory(System.Web.Hosting.VirtualDirectory vdir, System.Web.VirtualPath virtualDir, bool ignoreErrors) + 0xbc 字節    
  22:      System.Web.dll!System.Web.Compilation.BuildManager.CompileWebFile(System.Web.VirtualPath virtualPath = {System.Web.VirtualPath}) + 0x5d 字節    
  23:      System.Web.dll!System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(System.Web.VirtualPath virtualPath = {System.Web.VirtualPath}, bool noBuild, bool allowCrossApp, bool allowBuildInPrecompile, bool throwIfNotFound, bool ensureIsUpToDate) + 0x141 字節    
  24:      System.Web.dll!System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(System.Web.HttpContext context, System.Web.VirtualPath virtualPath, bool noBuild, bool allowCrossApp, bool allowBuildInPrecompile, bool throwIfNotFound, bool ensureIsUpToDate) + 0x70 字節    
  25:      System.Web.dll!System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(System.Web.VirtualPath virtualPath, System.Web.HttpContext context, bool allowCrossApp, bool throwIfNotFound) + 0x7e 字節    
  26:      System.Web.dll!System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(System.Web.VirtualPath virtualPath, System.Type requiredBaseType = {Name = "Page" FullName = "System.Web.UI.Page"}, System.Web.HttpContext context = {System.Web.HttpContext}, bool allowCrossApp) + 0x35 字節    
  27:      System.Web.dll!System.Web.UI.PageHandlerFactory.GetHandlerHelper(System.Web.HttpContext context, string requestType, System.Web.VirtualPath virtualPath = {System.Web.VirtualPath}, string physicalPath) + 0x20 字節    
  28:      System.Web.dll!System.Web.UI.PageHandlerFactory.System.Web.IHttpHandlerFactory2.GetHandler(System.Web.HttpContext context, string requestType, System.Web.VirtualPath virtualPath, string physicalPath) + 0x29 字節    
  29:      System.Web.dll!System.Web.HttpApplication.MapHttpHandler(System.Web.HttpContext context, string requestType, System.Web.VirtualPath path, string pathTranslated = "。。。。。。。。。。\\order\\default.aspx", bool useAppConfig) + 0xa8 字節    
  30:      System.Web.dll!System.Web.HttpApplication.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() + 0x81 字節    
  31:      System.Web.dll!System.Web.HttpApplication.ExecuteStep(System.Web.HttpApplication.IExecutionStep step = {System.Web.HttpApplication.MapHandlerExecutionStep}, ref bool completedSynchronously = true) + 0xb9 字節    
  32:      System.Web.dll!System.Web.HttpApplication.ApplicationStepManager.ResumeSteps(System.Exception error) + 0x13e 字節    
  33:      System.Web.dll!System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext context, System.AsyncCallback cb, object extraData) + 0xf8 字節    
  34:      System.Web.dll!System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest wr = {System.Web.Hosting.ISAPIWorkerRequestInProcForIIS7}) + 0x1a2 字節    
  35:      System.Web.dll!System.Web.HttpRuntime.ProcessRequestNoDemand(System.Web.HttpWorkerRequest wr) + 0x7d 字節    
  36:      System.Web.dll!System.Web.Hosting.ISAPIRuntime.ProcessRequest(System.IntPtr ecb, int iWRType) + 0xfd 字節    
  37:      [應用程序域轉換]    
  38:      [本機到托管的轉換]   

 

2.  嘗試過的處理思路

    我Attach到w3wp上去后,首次訪問目錄下的默認頁面,catch到ArgumentException異常,然后根據異常信息,追蹤到 TemplateParser.ParseFile -> ParseString -> ParseStringInternal -> ProcessBeginTag;然后我就嘗試了下列努力:

1. 該目錄下默認文件的<%@Page ....%>定義,屬性與其他文件並沒有任何不同(除了CodeBehind和Inherits的值),我把頁面里面的內容一點兒一點兒刪掉,最后是剩下空內容(只剩下head、body、form幾個元素)、空后台代碼,問題還依舊存在。

2. 我在這個目錄下面,新建了一個頁面(VS2010自動生成的,沒有添加任何元素或標簽),然后把這個新文件作為該目錄默認頁,發現問題還是存在。

3. 在第2步的基礎上,打開新默認頁后,我在URL中直接輸入舊的默認頁,頁面瞬間刷出來了。然后我就糾結了,這延時,與頁面內容毛的關系都木有,這異常信息也太坑爹了。

4. 出於嘗試一下,我試下該目錄下的其他文件,首次訪問會不會變慢。於是重啟IIS,然后發現首次訪問該目錄中的第一個文件(不論首次訪問的是哪個文件),都會耗時數秒;如果Attach到w3wp,都會Catch到這個異常。

5. 項目是從.net framework 1.1(VS2003)上直接升級過來的,以前03的版本,木有這個問題。然后google“asp.net 4.0 slow”,找到下面這個:

    Slow Performance — ASP .NET ASPNET_WP.EXE and CSC.EXE Running After Clicking Redirect Link

6. The very first time that the page is load, then the asp.net compile a lot of pages, almost every one found on the same dir, including modules, and dlls found on bin.也就是說,在首次請求一個目錄下的某個文件時,會把該目錄的所有文件都編譯一下。這樣做的好處是,把一個目錄的編譯操作都集中在首次訪問上,后續請求會比較快;但這樣帶來的問題是,如果編譯時間比較久,那第一個發起請求的人就杯具了。於是在配置文件中,設置batch="false",然后問題消失,首次請求的速度提上來了,attach上去也沒有異常了。

   

3.  解決方法

   部署的時候,記得在配置文件中,把debug和batch關閉,把optimizeCompilations打開:

    <compilation targetFramework="4.0" debug="false" batch="false" optimizeCompilations="true">

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM