2009-06-12 16 views
3

У меня есть общий HTTP-обработчик (* .ashx) в моем приложении ASP.Net, который выполняет некоторые базовые, но трудоемкие вычисления, распечатывая заявления о выполнении на выходе, поскольку он идет, чтобы информировать пользователя , Выполнение этих вычислений включает в себя чтение некоторых файлов данных, которые блокируются обработчиком при их использовании, поэтому важно, чтобы два вызова обработчика не запускались сразу.Одновременные запросы к обработчику HTTP не работают

Для этого я добавил переменную в кэш, которая указывает, что выполняется вычисление, это предотвращает отправку основного приложения в этот обработчик, если другой пользователь уже существует. В самом обработчике он проверяет, установлена ​​ли переменная 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

Нашел ответ самостоятельно, это не имеет ничего общего с веб-сервером или приложением, а просто для поведения браузера. Кажется, что если вы открываете несколько вкладок и переходите к одному и тому же URL-адресу в браузере, таком как Firefox или Chrome, браузер делает запросы последовательно, то есть он ждет завершения одного из них, прежде чем делать следующее. Открытие двух браузеров и сделать два запроса результатов в ожидаемом поведении

IIS, Asp.NET pipeline and concurrency

0

Если оба потока прочитать значение кэша INPROGRESS перед одним из них устанавливает его, тогда inprogress будет null в обоих случаях.

Думаю, вам может понадобиться блокировка здесь, поскольку у вас могут возникнуть проблемы с параллелизмом с вышеуказанным кодом.

+0

Я думаю, что может случиться, но это приведет лишь к основному приложению перенаправляет запросы назад к обработчику в любом случае, так как, если обновление не произойдет, тогда основное приложение все равно захочет обновить – RobV

+0

Я думаю, что наличие обоих потоков с нулевым кешем означает, что вы можете нажать контекст.Cache.Insert дважды, чтобы вы не блокировали второй запрос. Но это не проблема, которую вы описываете. Также может возникнуть подобная проблема синхронизации с линией «if (inprogress! = Null) this.Response.Redirect (« UpdateStats.ashx »); так как это должно будет вернуть обратно в браузер, чтобы перенаправить на обработчик. Как вы делаете свои 2 тестовых запроса? это в том же браузере? –

0

Вы уверены, что ваш веб-сервер многопоточен и может выполнять страницу одновременно? Не могли бы вы добавить заявления печати в начале ProcessRequest и в конце и посмотреть, если вы туда попадете?

+0

При отладке с использованием VS2008 второй запрос даже не попадет в метод ProcessRequest до первого завершения. Я запускаю IIS7 на Windows Server 2008 в своем ядро ​​Quad Core, поэтому я сильно мулифицирован – RobV

+0

Это не потому, что ваш процессор или ОС многопоточен, что ваш веб-сервер. Поскольку второй запрос не приходит в метод ProcessRequest до первого завершения, очевидно, что сервер обрабатывает запросы последовательно.Это ограничение серверного приложения, возможно, оно может быть настроено, у меня нет опыта с этим. Вы можете попытаться понять, как он работает с одновременными запросами на двух разных страницах, возможно, последовательная обработка происходит только на странице. Это также означает, что ваш механизм inprogress «бесполезен» на данный момент. – Ron

Смежные вопросы