Правильный способ пропустить выполнение страницы после ответа.RedirectToRoute
Я пишу анекдот. asp.net 4.5 приложение, использующее новые функции маршрутизации. У меня есть страница, на которой отображается некоторая информация об элементе. В событии Page_Load
я проверяю данные маршрута (идентификатор элемента) и разрешения пользователя, и если что-то не так (например, идентификатор для удаленного элемента), я использую Response.RedirectToRoute
, чтобы отправить их обратно на домашнюю страницу. Не проходят идти, не собирают $200.
Это имело смысл, пока я не попытался получить доступ к удаленному элементу и вместо домашней страницы я получил ошибку страница. Я немного покопался и обнаружил, что даже после использования RedirectToRoute
(в отличие от стандартного метода Redirect
) остальная часть кода страницы продолжает выполняться, что по крайней мере кажется расточительным (поскольку я просто собираюсь выбросить результаты) и выдает ошибки, когда необходимые данные не существуют.
Я сделал еще немного так майнинг и обнаружил невероятное зло то есть Response.End()
. Он делает то, что мне нужно, но даже страница MSDN говорит мне, что Response.End
это незаконнорожденное дитя древнего проклятого языка, и оно не годится для того, чтобы видеть дневной свет. Главным возражением, по-видимому, является сам факт такого ответа.End создает исключение, и это плохо сказывается на производительности. Я не самый опытный разработчик, поэтому я не совсем понимаю проблему, но мне трудно поверить, что создание исключения стоит дороже, чем загрузка всей веб-страницы. Обходные пути кажутся довольно сложными и чрезмерными для такой простой задачи, тем более что большинство страниц требуют какой-то проверки подлинности.
Что я должен делать в этой ситуации? Использовать Response.End
и просить прощения за мою дерзость? Сколотить какой-нибудь уродливый обходной путь? Или мой взгляд на проблему изначально неверен? Мне бы очень хотелось это знать.
Обновление: теперь, когда я подумал об этом немного больше, я задаюсь вопросом, есть ли у меня неправильный взгляд на проблему. Возможно, немедленное перенаправление-не лучший ответ для пользовательского опыта. Был бы я лучше? убрать все элементы управления в панель и использовать что-то вроде этого?
Private Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init
'Validation Code
If notValid Then
ControlsPanel.Visible = false
ErrorPanel.Visible = true
End If
End Sub
2 ответа:
Я, возможно, иду на крайность, не отвечая на вопрос напрямую, но мне понравилось видеть ваше обновление относительно пользовательского опыта. Я предпочитаю предложенный вами подход.
Я хотел бы дать ошибку 410 для идентификаторов, которые не являются допустимыми и расширить его немного с (переведено с C#):
Protected Sub ItemDoesNotExist() 'item does not exist, serve up error page ControlsPanel.Visible = False ErrorPanel.Visible = True 'add meta tags for noindex Dim mymeta As New HtmlMeta() mymeta.Name = "robots" mymeta.Content = "noindex" Page.Header.Controls.Add(mymeta) 'RESPOND WITH A 410 Response.StatusCode = 410 Response.Status = "410 Gone" Response.StatusDescription = "Gone" Response.TrySkipIisCustomErrors = True 'important for IIS7, otherwise the Custom error page for 404 shows. Page.Title = "item gone" End Sub
RedirectToRoute на самом деле является ответом wraps .Перенаправление передача
false
для завершения запроса-следовательно, запрос продолжается. Вы можете использовать HttpApplication.CompleteRequest как немедленный вызов для завершения запроса, чтобы не вызывались следующие события приложения.
Response.End
(и другие варианты перенаправления) бросаетThreadAbortException
, чтобы прервать поток обработки запроса, который на самом деле является плохим способом остановить обработку запроса. В .Чистый мир, исключение обработка всегда считается дорогостоящей, потому что CLR затем нужно искать в стеке все блоки обработки исключений, создавать трассировку стека и т. д. IMO,CompleteRequest
был введен в .NET 1.1, чтобы избежать того же, что на самом деле зависит от установки флага в ASP.NET код инфраструктуры для пропуска дальнейшей обработки, кроме событияEndRequest
.Еще один (и лучший) способ-использовать сервер.Перенесите и избегайте кругового перемещения клиента для установки перенаправления все вместе. Единственная проблема заключается в том, что клиент не будет видеть перенаправленный URL-адрес в адресной строке браузера. Я обычно предпочитаю этот метод.
Править
CompleteRequest
никогда не будет работать в случае страницы, где последующие события страницы будут по-прежнему вызываться, потому что страница является обработчиком, все ее события происходят в пределах одного (и текущего) события приложенияProcessRequest
. Таким образом, единственный способ, кажется, установить флаг и проверить этот флаг в переопределениях, таких какRender
,PreRender
,RaisePostBackEvent
и т.д.С точки зрения технического обслуживания, это имеет смысл иметь такую функциональность в базовом классе страницы (т. е. поддерживать флаг, предлагать метод
CompleteRequest
подклассам и переопределять методы событий жизненного цикла). Например,internal class PageBase: System.Web.UI.Page { bool _requestCompleted; protected void CompleteRequest() { Context.ApplicationInstance.CompleteRequest(); _requestCompleted = true; } protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument) { if (_requestCompleted) return; base.RaisePostBackEvent(sourceControl, eventArgument); } protected internal override void Render(HtmlTextWriter writer) { if (_requestCompleted) return; base.Render(writer); } protected internal override void OnPreRender(EventArgs e) { if (_requestCompleted) return; base.OnPreRender(e); } ... and so on }