2009-12-11 6 views
33

Внутри ASPX-страницы я хочу закончить ответ в определенных точках (не из-за ошибки), в зависимости от пути кода, так что ничего больше не будет отправлено обратно поток. Поэтому, естественно, используется:HttpResponse.End vs HttpResponse.Close vs HttpResponse.SuppressContent

Response.End(); 

Это приводит к ThreadAbortException, который by design.

Следующая, кажется, работает, но не выглядит как правильный подход, согласно this SO question:

Response.Flush(); 
Response.Close(); 

Итак, как об этом?

Response.Flush(); 
Response.SuppressContent = true 

, а затем просто позвольте странице закончить нормально.

Я мог бы просто обработать и проглотить ThreadAbortException, но я просто хочу узнать, есть ли что-то неправильное/gotchas с подходом SuppressContent?

Редактировать: Чтобы дать немного больше примеров. Скажем, у меня есть страница ASPX, в которой я могу изменить тип контента на один из нескольких вариантов. В зависимости от типа содержимого и сценария в данной точке кода я хочу предотвратить отправку большего количества контента клиенту. Предположим, что после того, как параметр SuppressContent установлен в значение true, нет проблемы с дальнейшим запуском на стороне сервера. Я просто не хочу, чтобы что-то еще было отправлено клиенту.

Изменить 2: MyPage.aspx - имеет главную страницу, которая может включать в себя стандартный контент, заголовки, колонтитулы и т.д. и т.п. Эта страница может оказать только как обычную страницу. Он также может просто выписать (например) XML-документ для загрузки. Если вы выписываете XML-документ (определенный при загрузке страницы), он очищает вывод, устанавливает тип содержимого в XML, записывает весь XML-выход, а затем, если он оставлен в обычном режиме, вы получаете остальную часть страницы ASPX-рендеринга, являющейся привязана к концу - это, очевидно, не требуется/ломает XML.

Редактировать 3: На данный момент я использую подход SuppressContent. Чтобы довести этот вопрос до конца, я повышаю щедрость и ставит вопрос другим способом: когда должен вы используете SuppressContent? Почему вы использовали его вместо Response.End?


Пожалуйста, смотрите ответ я предоставил ниже для решения я на самом деле в конечном итоге с, как я в конце концов нашел способ избежать ThreadAbortException при использовании response.end. Я уже не ответил на этот вопрос.


+0

Это звучит, как вам нужно внимательно изучить код, чтобы увидеть, что еще можно было бы выписывать в поток ответа после того, как вы закончили. Все это звучит как бит-спагетти. –

+0

Нет других ответов Response.Writes или ничего из кода. Проблема заключается в том, что если страница фактически выписывает XML-документ вместо обычного вывода HTML-страницы, как только я изменил тип контента на XML и написал XML-выход, я не хочу, чтобы оставшаяся часть страницы ASPX быть визуализированным - это, очевидно, сломает XML – AdaTheDev

ответ

4

обновление - предупреждение: есть лучший метод, не используйте это, вместо этого см. Ответ Этана!

Я бы не сказал, что есть веская причина, чтобы избежать ответа. Желая избежать затрат на ThreadAbortException, разрешив цикл запроса страницы, и у вас есть дополнительная работа, которая не нужна, кажется неправильной.

ThreadAbortException - особый тип исключения, предназначенный для прекращения выполнения потока (его автоматически отбрасывать, даже если он был пойман). Тем не менее, есть некоторые сценарии, где это может нанести вред (см. Содержимое сообщества, добавленное в конце ThreadAbortException).

Если вы не находитесь в одном из этих сценариев, вы должны придерживаться Response.End. Обратите внимание, что некоторые способы использования, do SuppressContent & Response.End, я думаю, в тех случаях, когда вы хотите избежать некоторых вещей, которые будут поступать из внутреннего Response.Flush.

+0

Я думаю, что это суммирует общую картину, которую я получаю от изучения этого. Посмотрел пару статей, используя подход SuppressContent/Response.End. Было также полезно указывать на раздел контента сообщества по ссылке. – AdaTheDev

+2

Обязательно прочитайте ответ @ Этана, вы никогда не должны использовать 'Response.End()'. –

+0

После прочтения, я полностью согласен. Добавление примечания в верхней части моего ответа. – eglasius

1

Что делать, если после вызова Response.SuppressContent = true ваша страница продолжает вносить изменения в записи в базе данных?

+0

Да, дальнейший код на стороне сервера будет выполнен, поэтому можно было бы сделать больше работы, например, работать с базами данных. В моем случае это не проблема; Я просто не хочу, чтобы на этот ответ был отправлен больше контента. – AdaTheDev

1

Насколько я понимаю код при отражении HttpResponse с использованием подхода Flush/SuppressContent сделает вас уязвимым для кода, пытающегося сделать изменения заголовка после флеша. Изменение заголовка после флеша даст HttpException.

Я бы использовал Response.End(), чтобы быть абсолютно уверенным, что ничто другое не может помешать ответу.

Если вы хотите продолжить выполнение, но также и короткое замыкание, то http-конвейер рассмотрит использование Response.Flush() и HttpContext.Current.ApplicationInstance.CompleteRequest() как Response.End(), когда контекст не находится в периоде отмены ,

+0

После того, как я выполнил команду flush/suppresscontent, изменений заголовков не будет. На самом деле, вероятно, на самом деле ничего действительно не произойдет. За исключением того, что, если я пишу XML-документ и соответствующим образом устанавливаю тип контента, я просто хочу предотвратить какой-либо дополнительный контент, обработанный ASPX-страницей (который нарушит XML, который я уже вынул). – AdaTheDev

+0

Метод CompleteRequest, похоже, не работает. После того, как это вызвано, больше содержимого все еще написано клиенту (это, к примеру, содержимое главной страницы, которое мне не нужно) – AdaTheDev

3

Это очень распространенный вопрос. И почти всегда бывает ошибкой называть что угодно, кроме Response.End(). Вот описание End() из MSDN:

Посылает все в настоящее время буферный вывод к клиенту, останавливает выполнение страницы и поднимает EndRequest события.

Это похоже на то, что вы хотите сделать. И вы заметите в последней части, что оно вызывает событие EndRequest. Это означает, что после вызова End() все данные очищаются клиентом, который был написан до конца(), сокет закрыт, а ресурсы освобождены, и ваша программа перестает обрабатывать запрос сразу.

+2

Yeah a Response.End() действительно работает для меня ЗА ИСКЛЮЧЕНИЕМ того, что вы всегда получаете исключение ThreadAbortException. Это не исключительный код, который попадает в Response.End(), поэтому он чувствует себя не так, что обращение с этим исключением становится нормой. Это заставило меня думать, что «должен быть другой путь» - поэтому я хотел знать, была ли какая-либо реальная проблема с использованием подхода SuppressContent. – AdaTheDev

0

Вы уверены, что правильная проекция? Какую предварительную обработку вы можете сделать, чтобы обеспечить отправку правильных заголовков, а затем придерживаться ее до тех пор, пока скрипт не выполнит свои задачи?

12

В итоге я нашел простое решение для использования Response.End() без получения исключения ThreadAbortException.

Response.Flush(); 
Response.End(); 

С моей оригинальный вопрос, я всегда пытался JUST в response.end() после отправки некоторого содержимого в поток ответа.

Похоже, что если у вас есть Response.End(), вы получаете исключение ThreadAbortException. Делая Флаш сразу перед Конец, исключение ThreadAbortException фактически не бросается.

Кажется, работает здорово - не ThreadAbortException не бросают сейчас, когда я использую Response.End

+7

Я проголосовал за этот ответ, но после фактического тестирования я узнал, что это не работает. Чтобы протестировать его самостоятельно: в своем обложке кода Response.End в блоке catch try и внутри блока catch выполните response.write (ex.Message). Вы увидите, что «Thread был прерван». сообщение. Тем не менее, похоже, что нет другого способа прекратить ответ и прекратить выполнение кода, поэтому просто закройте свой код в try catch и внутри catch сделайте Server.ClearError(); * P.S. Я не уверен, какова будет фактическая точка этого ...* –

+2

Исключение * * выбрано, и в любом случае первое, что делает End(), является flush *, поэтому я не вижу, как это может измениться. И это не так. * «Отправляет весь текущий буферизованный вывод клиенту» http://msdn.microsoft.com/en-us/library/system.web.httpresponse.end%28VS.80%29.aspx – mhenry1384

+0

Я также просто проверил это. Я думаю, что Response.End всегда выдает исключение, если контекст еще не находится в периоде отмены, что бы это ни значило. http://referencesource.microsoft.com/#System.Web/HttpResponse.cs,4a66c734706db954 – user420667

37

Я знаю, что это старый вопрос, но я в том числе это в интересах тех, кто может наткнуться на этот после. Я искал ошибку, которая привела меня к рассмотрению моего использования Response.End и обнаружила сообщение MSDN через год после этого вопроса, который можно было бы суммировать как «Никогда, никогда не используйте Response.End».Вот что говорит Томас Марквардт, который проектировал интегрированный трубопровод для IIS7:

Метод End также включен в мой список «никогда не использовать». Лучший способ остановить запрос - вызвать HttpApplication.CompleteRequest. Метод End существует только потому, что мы пытались быть совместимыми с классическим ASP, когда 1.0 был выпущен. Классический ASP имеет метод Response.End, который завершает обработку сценария ASP. Чтобы подражать этому поведению, метод End в ASP.NET пытается создать исключение ThreadAbortException. Если это будет успешным, вызывающий поток будет прерван (очень дорого, не подходит для производительности), и конвейер перейдет к событию EndRequest. Исключение ThreadAbortException, в случае успеха, конечно, означает, что поток отключается, прежде чем он сможет вызывать код, поэтому вызов End означает, что после этого вы не будете вызывать код. Если метод End не способен поднять исключение ThreadAbortException, он вместо этого будет очищать байты ответа от клиента, но он делает это синхронно, что очень плохо для производительности, и когда код пользователя после завершения End выполняется, конвейер перескакивает вперед к уведомлению EndRequest. Написание байтов для клиента является очень дорогостоящей операцией, особенно если клиент находится на полпути по всему миру и использует модем 56k, поэтому лучше всего отправлять байты асинхронно, что и мы делаем, когда запрос заканчивается обычным способом. Промывка синхронно очень плохая. Итак, чтобы подвести итог, вы не должны использовать End, но использование CompleteRequest отлично. В документации для End должно быть указано, что CompleteRequest - лучший способ пропустить уведомление EndRequest и выполнить запрос.

От http://blogs.msdn.com/b/aspnetue/archive/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation.aspx

+5

Отличная находка. Это должно быть окончательно принятым ответом. –

+0

+1 интересная находка. Я обязательно буду использовать CompleteRequest в следующий раз, когда я столкнулся с этим сценарием. Необходимо проявлять осторожность, так как это не то же самое поведение, что и код, выполняемый после вызова «и код после вызова метода CompleteRequest». Только незначительная вещь, на которую нужно обратить внимание. – eglasius

+0

+1 это решило проблему для меня тоже. У меня было два вопроса, способствующих этому, которые необходимо было решить, поэтому, если кто-то применит это, и это не поможет, подумайте об этом: http://stackoverflow.com/questions/15586309/asp-net-mvc-4-api -download-of-docx-failing-in-ie8/15687482 # comment59166866_15687482 – dlatikay

Смежные вопросы