Пользователь попадает на страницу spawn.aspx, которая затем порождает полдюжины потоков, все страницы рендеринга используют
((System.Web.IHttpHandler)instance).ProcessRequest(reference to spawn HTTPContext);
Не беспокойтесь о том, что ASP.Net, по-видимому, отправляет пользователю 7 ответов для 1 запроса, обрабатывается эта часть и отправляется только один ответ.
Проблема заключается в том, что в среде с высоким трафиком (наша производственная среда) со многими потоками (квад-квадроциклы) возникает ошибка:
System.IndexOutOfRangeException at System.collections.ArrayList.Add at System.Web.ResponseDependencyList.AddDependencies(String[] items, String argname, Boolean cloneArray, DateTime utcDepTime) at System.Web.ResponseDependencyList.AddDependencies(String[] items, String argname, Boolean cloneArray, String requestVritualPath) at System.Web.UI.Page.AddWrappedFileDependencies(Object virtualFileDependencies) at ASP.spawned_page_no_1_aspx.FrameworkInitialize() at System.Web.UI.Page.ProcessRequest
Мы не можем дублировать его в другом месте. Мой коллега полагает, что это связано с тем, что я повторно использую оригинальный HTTPContext и передаю его в другие потоки, и что он не Thread-Safe.
Следуя этой логике, я попытался сделать новый HTTPContext для передачи в потоки. Но его части, похоже, "не сочетаются". В частности, мне нужно получить объект Session в новый HTTPContext. Я предполагаю, что хотел бы получить и другие части, такие как Cache. Для записи HTTPContext.Current.Session.IsSynchronized является ложным.
Мои вопросы:
- Считаете ли вы, что ошибка связана с использованием HTTPContext для потоков?
- Как я могу это исправить?
- Если исправление дублирует HTTPContext для каждого потока, как я могу получить Session (и Cache) в новый? Запрос и ответ поступают в ctor, но сеанс не настраивается.
Изменить: Подробнее
Итак, вернемся к этому утверждению: "Не беспокойтесь о том, что ASP.Net, по-видимому, отправляет пользователю 7 ответов для 1 запроса, эта часть обрабатывается и отправляется только один ответ". Огромный поклонник Раймонда Чена, я согласен с вами: "Теперь у вас есть две проблемы" - разумное утверждение в отсутствие дополнительной информации.
Что на самом деле происходит, так это то, что я создаю Excel-документ для отправки назад. На странице spawn.aspx он настраивает некоторую информацию о состоянии, включая тот факт, что она визуализируется, и объект, для которого выполняется рендеринг. Каждая порожденная страница получает эту информацию и блокирует до тех пор, пока ее очередь не будет показана объекту. Если буквально выглядит так:
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
if (this.RenderToExcel)
{
Deadlocker.SpinUntilCurrent(DeadLockToken);
RenderReport(this, this.XLSWriter);
Deadlocker.Remove(DeadLockToken);
}
else
base.Render(writer);
}
Но вся обработка до этого момента - доступ к базе данных, контроль над иерархией, все это делается параллельно. И там много - достаточно, чтобы разделить его, оставив его на Render, сократить общее время в более чем половине.
И лучшая его часть - ничто не должно было быть переписано для рендеринга Excel. Все элементы управления знают, как заставить себя преуспеть, и вы можете посещать каждую созданную страницу независимо (что "нормальный случай" на самом деле - отчет Excel - это всего лишь совокупность всех порожденных страниц.)
Итак, я понял, что конечный результат будет "вы не можете этого сделать, вам нужно переосмыслить подход", но мне пришлось хотя бы попробовать, потому что тот факт, что все работает так красиво, не дублируя никакой логики или любой код или необходимость абстрагировать что-либо просто так идеально. И это только многопоточность, что проблема, если я визуализирую страницы последовательно, все в порядке, просто медленно.