Является ли Response.End() вредным?
В этой статье базы знаний говорится, что 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()
?
ссылка: запись в блоге Рика Страля.
Исходя из полученной информации, мой ответ: да, Response.End
вредно, но полезно в некоторых ограниченных случаях.
- использование
Response.End()
как неуловимый бросок, чтобы немедленно прекратитьHttpResponse
в исключительных условиях. Может быть полезно и во время отладки. избежатьResponse.End()
завершить рутинные ответы. - использование
Response.Close()
немедленно закрыть соединение с клиентом. Согласно этому сообщению в блоге MSDN, этот метод не предназначен для обычной обработки HTTP-запросов. Маловероятно, что у вас будет веская причина для вызова этого метода. - использование
CompleteRequest()
закончить нормальный запрос.CompleteRequest
заставляет конвейер ASP.NET переходить кEndRequest
событие, после текущегоHttpApplication
событие завершено. Так что если вы позвонитеCompleteRequest
, затем напишите что-то еще в ответ, запись будет отправлена клиенту.
Изменить - 13 апреля 2011
Дополнительная ясность доступна здесь:
- Полезный пост в блоге MSDN
- Полезный анализ Джон Рид
8 ответов
Если вы использовали регистратор исключений в своем приложении, оно будет смягчено ThreadAbortException
с этих доброкачественных Response.End()
звонки. Я думаю, что это способ Microsoft сказать "Сбей это!"
Я бы только использовал Response.End()
если было какое-то исключительное условие и никакие другие действия были невозможны. Может быть, регистрация этого исключения может фактически указывать на предупреждение.
TL;DR
Первоначально я рекомендовал вам просто заменить все ваши вызовы [Response.End] на [...] вызовы CompleteRequest(), но если вы хотите избежать обработки обратной передачи и рендеринга html, вам нужно добавить [...] также переопределяет.
Джон Рид, "Окончательный анализ"
За MSDN, Джон Рид и Ален Ренон:
Производительность ASP.NET - Управление исключениями - Написание кода, исключающего исключения
Методы Server.Transfer, Response.Redirect, Response.End вызывают исключения. Каждый из этих методов внутренне вызывает Response.End. Вызов Response.End, в свою очередь, вызывает исключение ThreadAbortException.
Решение ThreadAbortException
HttpApplication.CompleteRequest() устанавливает переменную, которая заставляет поток пропускать большинство событий в конвейере событий HttpApplication [-] не цепочку событий страницы, а цепочку событий приложения.
...
создайте переменную уровня класса, которая помечает, должна ли страница завершиться, и затем проверьте переменную перед обработкой ваших событий или рендерингом вашей страницы. [...] Я бы порекомендовал просто переопределить методы RaisePostBackEvent и Render
Response.End и Response.Close не используются в обычной обработке запросов, когда важна производительность. Response.End - это удобное, жесткое средство завершения обработки запроса с соответствующим снижением производительности. Response.Close предназначен для немедленного завершения HTTP-ответа на уровне IIS/ сокета и вызывает проблемы с такими вещами, как KeepAlive.
Рекомендуемый метод завершения запроса ASP.NET - HttpApplication.CompleteRequest. Имейте в виду, что рендеринг ASP.NET придется пропустить вручную, поскольку HttpApplication.CompleteRequest пропускает остальную часть конвейера приложения IIS/ASP.NET, а не конвейер страницы ASP.NET (который является одним из этапов в конвейере приложения).
Код
Copyright © 2001-2007, C6 Software, Inc, насколько я мог судить.
Ссылка
HttpApplication.CompleteRequest
Заставляет ASP.NET обходить все события и фильтрацию в цепочке выполнения конвейера HTTP и напрямую выполнять событие EndRequest.
Response.End
Этот метод предоставляется только для совместимости с ASP, то есть для совместимости с технологией веб-программирования на основе COM, которая предшествовала ASP.NET.preceded ASP.NET. [Акцент добавлен]
Response.Close
Этот метод прерывает соединение с клиентом внезапным образом и не предназначен для обычной обработки HTTP-запроса. [Акцент добавлен]
Этот вопрос появляется в верхней части всех запросов 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()
На вопрос "Я до сих пор не знаю разницу между Response.Close и CompleteRequest()", я бы сказал:
Предпочитаю CompleteRequest(), не используйте Response.Close().
См. Следующую статью для хорошо сделанного резюме этого случая.
Имейте в виду, что даже после вызова CompleteRequest () некоторый текст (например, выделенный из кода ASPX) будет добавлен к потоку вывода ответа. Вы можете предотвратить это, переопределив методы Render и RaisePostBackEvent, как описано в следующей статье.
Кстати: я согласен с тем, чтобы запретить использование Response.End(), особенно при записи данных в поток http для эмуляции загрузки файла. Мы использовали Response.End () в прошлом, пока наш файл журнала не заполнился исключениями ThreadAbortExceptions.
Я не согласен с утверждением " Ответ. И это вредно ". Это определенно не вредно. Response.End делает то, что говорит; это заканчивает выполнение страницы. Использование отражателя, чтобы увидеть, как это было реализовано, следует рассматривать только как поучительный.
Моя 2cent Рекомендация
ИЗБЕГАЙТЕ используя Response.End()
в качестве контроля потока.
Использовать Response.End()
если вам нужно остановить выполнение запроса и знать, что (как правило)* ни один код не будет выполнен после этой точки.
* Response.End()
и ThreadAbortException s.
Response.End()
генерирует исключение ThreadAbortException как часть его текущей реализации (как отмечено в OP).
ThreadAbortException - это особое исключение, которое может быть перехвачено, но оно будет автоматически вызвано снова в конце блока catch.
Чтобы узнать, как написать код, который должен иметь дело с ThreadAbortExceptions, см. Ответ @Mehrdad на SO. Как я могу обнаружить threadabortexception в блоке finally, где он ссылается на метод RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup и области ограниченного выполнения
Упомянутая статья Рика Строля поучительна, и обязательно прочитайте комментарии. Обратите внимание, что проблема Strahl была конкретной. Он хотел передать данные клиенту (изображение), а затем обработать обновление базы данных отслеживания обращений, которое не замедляло обслуживание изображения, что создавало проблему для выполнения чего-либо после вызова Response.End.
Я никогда не думал об использовании Response.End() для управления потоком программ.
Однако Response.End() может быть полезен, например, при передаче файлов пользователю.
Вы записали файл в ответ и не хотите, чтобы в ответ добавлялось что-либо еще, так как это может повредить ваш файл.
Я использовал только Response.End() в качестве механизма тестирования / отладки.
<snip>
Response.Write("myVariable: " + myVariable.ToString());
Response.End();
<snip>
Судя по тому, что вы опубликовали с точки зрения исследований, я бы сказал, что это будет плохой дизайн, если он потребует ответа.
Я использовал Response.End() как в.NET, так и в Classic ASP для принудительного прекращения работы. Например, я использую его, когда есть определенное количество попыток входа в систему. Или когда защищенная страница принимается от неаутентифицированного входа в систему (грубый пример):
if (userName == "")
{
Response.Redirect("......");
Response.End();
}
else
{
.....
При передаче файлов пользователю, который я бы использовал Flush, конец может вызвать проблемы.
На классическом asp у меня был TTFB (время до первого байта) от 3 до 10 секунд на некоторых вызовах ajax, намного больше, чем TTFB на обычных страницах с большим количеством вызовов SQL.
Возвращенный ajax был сегментом HTML, который нужно вставить в страницу.
TTFB был на несколько секунд длиннее, чем время рендеринга.
Если я добавлю response.end после рендера, TTFB будет значительно уменьшен.
Я мог бы получить тот же эффект, испуская " body> html>", но это, вероятно, не работает при выводе json или xml; здесь response.end нужен.