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, и Ален Ренон:

Производительность ASP.NET - Управление исключениями - Запись кода, исключающего исключения

. Server.Transfer, Response.Redirect, Response.End все методы повышают исключения. Каждый из этих методов внутренне вызывает Response.End. Призыв к Response.End, в свою очередь, вызывает исключение ThreadAbortException.

ThreadAbortException Solution

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, насколько я мог бы сказать.


Ссылка

HttpApplication.CompleteRequest

Заставляет ASP.NET обходить все события и фильтровать в цепочке HTTP-конвейера выполнение и непосредственное выполнение события EndRequest.

Response.End

Этот метод предоставляется только для совместимости с ASP, то есть для совместимость с технологией веб-программирования на основе COM, которая предшествовала ASP.NET.preceded ASP.NET. [Акцент добавлен]

Response.Close

Этот метод резко прекращает соединение с клиентом и не предназначен для нормальной обработки 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 нужен.