Is Response.End() считается вредным?
В этой статье KB говорится, что ASP.NET Response.End()
прерывает поток.
Отражатель показывает, что он выглядит так:
public void End()
{
if (this._context.IsInCancellablePeriod)
{
InternalSecurityPermissions.ControlThread.Assert();
Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));
}
else if (!this._flushing)
{
this.Flush();
this._ended = true;
if (this._context.ApplicationInstance != null)
{
this._context.ApplicationInstance.CompleteRequest();
}
}
}
Это кажется мне довольно суровым. Как говорится в статье в KB, любой код в приложении, следующий за Response.End()
, не будет выполнен, что нарушает принцип наименьшего удивления. Это почти как Application.Exit()
в приложении WinForms. Исключение прерывания потока, вызванное Response.End()
, не является захватывающим, поэтому окружающий код в try
... finally
не будет удовлетворять.
Это заставляет меня задаться вопросом, следует ли всегда избегать Response.End()
.
Может ли кто-нибудь предложить, когда следует использовать Response.End()
, когда Response.Close()
и когда HttpContext.Current.ApplicationInstance.CompleteRequest()
?
ref: Запись в блоге Рика Страхла.
На основании ввода, который я получил, мой ответ: Да, Response.End
вреден, но он полезен в некоторых ограниченных случаях.
- используйте
Response.End()
как неуловимый бросок, чтобы немедленно завершить HttpResponse
в исключительных условиях. Может быть полезно и при отладке. Избегайте Response.End()
для завершения стандартных ответов.
- используйте
Response.Close()
, чтобы немедленно закрыть соединение с клиентом. Per это сообщение в блоге MSDN, этот метод не предназначен для обычной обработки запросов HTTP. Его маловероятно, что у вас будет веская причина назвать этот метод.
- используйте
CompleteRequest()
для завершения обычного запроса. CompleteRequest
заставляет конвейер ASP.NET перейти к событию EndRequest
после завершения текущего события HttpApplication
. Поэтому, если вы вызываете CompleteRequest
, а затем пишите что-то еще в ответ, запись будет отправлена клиенту.
Редактировать - 13 апреля 2011 г.
Дополнительная ясность доступна здесь:
- Полезный пост в блоге MSDN
- Полезный анализ Джона Рида
Ответы
Ответ 1
Если вы использовали регистратор исключений в своем приложении, он будет орошен с помощью ThreadAbortException
от этих доброкачественных вызовов Response.End()
. Я думаю, что это Microsoft способ сказать "Сбейте это!".
Я использовал бы только Response.End()
, если бы было какое-то исключительное условие, и никаких других действий не было. Возможно, тогда регистрация этого исключения может фактически указывать на предупреждение.
Ответ 2
TL; DR
Первоначально я рекомендовал вам просто заменить все ваши звонки на [Response.End] с вызовами [...] CompleteRequest(), но если вы хотите избежать после обратной обработки и рендеринга html вам нужно будет добавить [...] переопределения как хорошо.
Джон Рид, "Окончательный анализ"
В MSDN, Jon Reid, и Ален Ренон:
. Server.Transfer, Response.Redirect, Response.End все методы повышают исключения. Каждый из этих методов внутренне вызывает Response.End. Призыв к Response.End, в свою очередь, вызывает исключение ThreadAbortException.
HttpApplication.CompleteRequest() устанавливает переменную, которая вызывает поток пропустить большинство событий в конвейере событий HttpApplication [-], а не Целевая цепочка событий, но цепочка событий приложения.
...
создать переменную уровня класса, которая будет флаг, если страница должна завершиться, а затем проверьте переменную до обработки ваших событий или рендеринга вашей страницы. [...] Я бы рекомендовал просто переопределить методы RaisePostBackEvent и Render
Response.End и Response.Close не используются в обычной обработке запросов, когда
производительность важна. Response.End - удобное, тяжелое средство
завершение обработки запроса с соответствующим штрафом за производительность.
Response.Close - для немедленного прекращения ответа HTTP в IIS/socket
и вызывает проблемы с такими вещами, как KeepAlive.
Рекомендуемый метод завершения запроса ASP.NET:
HttpApplication.CompleteRequest. Имейте в виду, что рендеринг ASP.NET будет иметь
для пропусков вручную, поскольку HttpApplication.CompleteRequest пропускает остальную часть
конвейер приложений IIS/ASP.NET, а не конвейер страницы ASP.NET(который
один этап в приложении).
код
Copyright © 2001-2007, C6 Software, Inc, насколько я мог бы сказать.
Ссылка
Заставляет ASP.NET обходить все события и фильтровать в цепочке HTTP-конвейера выполнение и непосредственное выполнение события EndRequest.
Этот метод предоставляется только для совместимости с ASP, то есть для совместимость с технологией веб-программирования на основе COM, которая предшествовала ASP.NET.preceded ASP.NET. [Акцент добавлен]
Этот метод резко прекращает соединение с клиентом и не предназначен для нормальной обработки HTTP-запросов. [Акцент добавлен]
Ответ 3
Этот вопрос появляется в верхней части всех поисковых запросов Google для информации о response.end, поэтому для других поисковых запросов, таких как я, которые хотят размещать CSV/XML/PDF и т.д. в ответ на событие без отображения всей страницы ASPX, вот как Я делаю это. (переопределение методов визуализации слишком сложно для такой простой задачи IMO)
// Add headers for a csv file or whatever
Response.ContentType = "text/csv"
Response.AddHeader("Content-Disposition", "attachment;filename=report.csv")
Response.AddHeader("Pragma", "no-cache")
Response.AddHeader("Cache-Control", "no-cache")
// Write the data as binary from a unicode string
Dim buffer As Byte()
buffer = System.Text.Encoding.Unicode.GetBytes(csv)
Response.BinaryWrite(buffer)
// Sends the response buffer
Response.Flush()
// Prevents any other content from being sent to the browser
Response.SuppressContent = True
// Directs the thread to finish, bypassing additional processing
HttpContext.Current.ApplicationInstance.CompleteRequest()
Ответ 4
В вопросе "Я все еще не знаю разницы между Response.Close и CompleteRequest()" Я бы сказал:
Вы предпочитаете CompleteRequest(), не используйте Response.Close().
См. в следующей статье для скважины -достаточное резюме этого случая.
Помните, что даже после вызова метода CompleteRequest() к потоку ответов будет добавлен текст (например, redndered from ASPX code). Вы можете предотвратить его, переопределив методы Render и RaisePostBackEvent, как описано в в следующей статье.
Кстати: я согласен с предотвращением использования Response.End(), особенно при записи данных в HTTP-поток для эмуляции загрузки файлов. Мы использовали Response.End() в прошлом, пока наш файл журнала не заполнил ThreadAbortExceptions.
Ответ 5
Я не согласен с утверждением "Response.End вредно". Это определенно не вредно. Response.End делает то, что он говорит; он завершает выполнение страницы. Использование отражателя для просмотра того, как оно было реализовано, должно рассматриваться только как поучительное.
Моя Рекомендация 2cent
ИЗБЕГАЙТЕ, используя Response.End()
как поток управления.
DO используйте Response.End()
, если вам нужно прекратить выполнение запроса, и имейте в виду, что (как правило) * код не будет выполняться после этой точки.
* Response.End()
и ThreadAbortException s.
Response.End()
генерирует исключение ThreadAbortException как часть его текущей реализации (как отмечено OP).
ThreadAbortException - особое исключение, которое можно поймать, но он будет автоматически снова поднят в конце блока catch.
Чтобы узнать, как писать код, который должен иметь дело с ThreadAbortExceptions, см. @Mehrdad ответ SO Как я могу обнаружить threadabortexception в блоке finally, где он ссылается на RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup Method и Ограниченные области выполнения
статья Рика Страгла, поучительная, и обязательно прочитайте комментарии. Обратите внимание, что проблема Strahl была конкретной. Он хотел получить данные на клиенте (изображение), а затем обработать обновление базы данных отслеживания удалений, которое не замедлит показ изображения, что сделало его проблемой сделать что-то после ответа Response.End.
Ответ 6
Я никогда не рассматривал использование Response.End() для управления потоком программы.
Однако Response.End() может быть полезен, например, при обслуживании файлов для пользователя.
Вы написали файл в ответ, и вы не хотите, чтобы в ответ добавлялось что-то еще, так как оно может повредить ваш файл.
Ответ 7
Я использовал Response.End() как в .NET, так и в Classic ASP для принудительного прекращения вещей раньше. Например, я использую его, когда есть количество попыток входа в систему. Или когда защищенная страница находится в доступе от неавторизованного входа (пример):
if (userName == "")
{
Response.Redirect("......");
Response.End();
}
else
{
.....
При обслуживании файлов пользователю я использую Flush, End может вызвать проблемы.
Ответ 8
Я использовал Response.End() в качестве механизма тестирования/отладки
<snip>
Response.Write("myVariable: " + myVariable.ToString());
Response.End();
<snip>
Судя по тому, что вы опубликовали с точки зрения исследований, я бы сказал, что это будет плохой дизайн, если потребуется Response.End
Ответ 9
На классическом asp у меня был TTFB (время до первого байта) от 3 до 10 секунд на некоторых вызовах ajax, намного больше, чем TTFB на обычных страницах с большим количеством вызовов SQL.
Возвращенный ajax был сегментом HTML, который нужно вставить в страницу.
TTFB был на несколько секунд длиннее, чем время рендеринга.
Если я добавлю response.end после рендера, TTFB будет значительно уменьшен.
Я мог бы получить тот же эффект, испуская "</body> </html>", но это, вероятно, не работает при выводе json или xml; здесь response.end нужен.