Является ли 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 будет значительно уменьшен.

Я мог бы получить тот же эффект, испуская "", но это, вероятно, не работает при выводе json или xml; здесь response.end нужен.

Другие вопросы по тегам