【问题标题】:Simultaneous requests to a HTTP Handler not working对 HTTP 处理程序的同时请求不起作用
【发布时间】:2009-06-12 08:33:01
【问题描述】:

我的 ASP.Net 应用程序中有一个通用 HTTP 处理程序 (*.ashx),它执行一些基本但耗时的计算,将进度语句打印到输出,以便让用户了解情况。执行这些计算涉及读取一些在使用时被处理程序锁定的数据文件,因此对处理程序的两次调用不要同时开始处理是很重要的。

为了实现这一点,我在缓存中添加了一个变量来指示计算正在进行中,这样可以防止主应用程序在另一个用户已经存在的情况下将用户发送到此处理程序。在 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...
}

【问题讨论】:

    标签: asp.net iis iis-7 httphandler


    【解决方案1】:

    我自己偶然发现了答案,这与 Web 服务器或应用程序无关,而仅与浏览器行为有关。似乎如果您在 Firefox 或 Chrome 等浏览器中打开多个选项卡并导航到相同的 URL,则浏览器会按顺序发出请求,即它会等待一个选项卡完成后再发出下一个。打开两个浏览器并发出两个请求会产生预期的行为

    IIS, Asp.NET pipeline and concurrency

    【讨论】:

      【解决方案2】:

      如果两个线程在其中一个设置它之前读取缓存值 inprogress ,那么 inprogress 在这两种情况下都将为空。

      我认为您可能需要在此处进行一些锁定,因为上述代码可能存在一些并发问题。

      【讨论】:

      • 我猜这可能会发生,但这只会导致主应用程序将请求重定向回处理程序,因为如果更新没有发生,那么主应用程序仍然需要更新
      • 我认为让两个线程都具有空缓存意味着您可以点击 context.Cache.Insert 两次,因此您不会阻止第二个请求。但这不是你描述的问题。 “if (inprogress != null) this.Response.Redirect("UpdateStats.ashx");”行也可能存在类似的时间问题因为这将不得不往返浏览器以重定向到处理程序。你是如何提出你的 2 个测试请求的?是在同一个浏览器中吗?
      【解决方案3】:

      您确定您的网络服务器是多线程的并且可以同时执行页面吗?您能否在 ProcessRequest 的开头和结尾添加打印语句,看看您是否同时进入那里?

      【讨论】:

      • 使用 VS2008 进行调试时,第二个请求甚至不会进入 ProcessRequest 方法,直到第一个请求完成。我在我的四核开发盒上的 Windows Server 2008 上运行 IIS7,所以我的多线程处理很重
      • 这并不是因为您的 CPU 或操作系统是多线程的,而您的网络服务器是多线程的。由于第二个请求在第一个请求完成之前没有进入 ProcessRequest 方法,很明显服务器是按顺序处理请求的。这是服务器应用程序的限制,也许可以配置,我没有这方面的经验。您可以尝试查看它如何处理两个不同页面上的同时请求,也许顺序处理仅在每页发生。这也意味着您的进度机制目前“无用”。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-05
      • 2012-08-30
      • 1970-01-01
      相关资源
      最近更新 更多