2009-06-12 54 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