2009-06-12 53 views
3

我在ASP.Net應用程序中有一個通用HTTP處理程序(* .ashx),它執行一些基本但耗時的計算打印進度語句的輸出,因爲它會通知用戶。執行這些計算包括讀取處理程序在使用它們時鎖定的一些數據文件,因此對處理程序的兩個調用不會立即開始處理很重要。對HTTP處理程序不起作用的同時請求

爲了達到這個目的,我在緩存中添加了一個變量,表示正在進行計算,這可以防止主應用程序將用戶發送給此處理程序,如果其他用戶已經在那裏。在Handler本身中,它檢查是否設置了Cache變量,並且如果設置了Cache值,應該將用戶發送回主應用程序。但是當我通過訪問處理程序兩次來測試這個訪問時,一個訪問執行得很好,第二個訪問位於那裏,直到第一個訪問結束時才執行任何操作。將IsReusable設置爲true沒有區別。

任何人有任何想法,爲什麼會發生這種情況?下面

代碼:

public class UpdateStats : IHttpHandler 
{ 
    private HttpContext _context; 

    public const String UpdateInProgressCacheKey = "FAHLeagueWebUpdateInProgress"; 

    public void ProcessRequest(HttpContext context) 
    { 
     //Use a Cache variable to ensure we don't call multiple updates 
     Object inprogress = context.Cache[UpdateInProgressCacheKey]; 
     if (inprogress != null) 
     { 
      //Already updating 
      context.Response.Redirect("Default.aspx"); 
     } 
     else 
     { 
      //Set the Cache variable so we know an Update is happening 
      context.Cache.Insert(UpdateInProgressCacheKey, true, null, DateTime.Now.AddMinutes(10), Cache.NoSlidingExpiration); 
     } 

     context.Response.Clear(); 
     context.Response.ContentType = "text/html"; 
     this._context = context; 

     context.Response.Write("<pre>Please wait while we Update our Statistics, you will be automatically redirected when this finishes...\n\n"); 

     //Get the Stats 
     Statistics stats = new Statistics(context.Server); 

     //Subscribe to Update Progress Events 
     stats.UpdateProgress += this.HandleUpdateProgress; 

     //Update 
     String force = context.Request.QueryString["force"]; 
     stats.UpdateStats((force != null)); 

     //Remove the Cache variable 
     context.Cache.Remove(UpdateInProgressCacheKey); 

     context.Response.Write("</pre>"); 
     context.Response.Write("<meta http-equiv=\"refresh\" content=\"0;URL=Default.aspx\" />"); 
     context.Response.Write("<p>If you are not automatically redirected please click <a href=\"Default.aspx\">here</a></p>"); 
    } 

    private void HandleUpdateProgress(String message) 
    { 
     this._context.Response.Write(message + "\n"); 
     this._context.Response.Flush(); 
    } 

    public bool IsReusable 
    { 
     get 
     { 
      return false; 
     } 
    } 
} 

編輯

增加從主應用程序的母版頁中的代碼:

public partial class FAH : System.Web.UI.MasterPage 
{ 
    private Statistics _stats; 

    protected void Page_Init(object sender, EventArgs e) 
    { 
     this._stats = new Statistics(this.Server); 
     if (this._stats.StatsUpdateNeeded) 
     { 
      //If the Cache variable is set we're already updating 
      Object inprogress = Cache[UpdateStats.UpdateInProgressCacheKey]; 
      if (inprogress != null) this.Response.Redirect("UpdateStats.ashx"); 
     } 
    } 
    //etc... 
} 

回答

6

自己偶然發現了答案,這與Web服務器或應用程序無關,而僅僅是與瀏覽器行爲有關。看起來,如果您打開多個選項卡並導航到瀏覽器中的相同URL(例如Firefox或Chrome),瀏覽器將按順序發出請求,即在等待下一個請求前等待完成。打開兩個瀏覽器,使兩個請求導致預期的行爲

IIS, Asp.NET pipeline and concurrency

0

如果兩個線程一個之前讀取緩存值INPROGRESS他們設置它,然後在兩種情況下進展將是空的。

我想你可能需要一些鎖定在這裏,因爲你可能有一些併發問題與上面的代碼。

+0

我想這可能發生,但如果更新不因爲這隻會導致主要應用重定向請求回無論如何處理程序發生然後主應用程序仍然需要更新 – RobV 2009-06-12 08:50:11

+0

我認爲兩個線程與空的緩存意味着你可以擊中context.Cache.Insert兩次,所以你不會阻止第二個請求。但這不是你所描述的問題。 「if(inprogress!= null)this.Response.Redirect(」UpdateStats.ashx「);也可能存在類似的時間問題。」因爲這將不得不返回瀏覽器以重定向到處理程序。 你是怎麼做你的2測試請求?它在同一瀏覽器中嗎? – 2009-06-12 13:34:47

0

你確定你的web服務器是多線程的,並且可以同時執行頁面嗎?您可以在ProcessRequest的開始處添加打印語句,並在最後看看您是否同時進入?

+0

使用VS2008進行調試時,第二個請求在第一次完成之前不會進入ProcessRequest方法。我在我的四核心開發箱上運行Windows Server 2008上的IIS7,因此我的沉重負擔 – RobV 2009-06-12 09:32:07

+0

這不是因爲你的CPU或OS是多線程的,你的網絡服務器是。由於第二次請求在第一次完成之前沒有進入ProcessRequest方法,很明顯服務器會按順序處理請求。這是服務器應用程序的限制,也許可以配置,我沒有經驗。您可以嘗試查看它在兩個不同頁面上同時發生的請求時的行爲,也許順序處理只發生在每個頁面上。這也意味着你的進行中機制目前是「無用的」。 – Ron 2009-06-12 14:05:04