2015-02-16 8 views
1

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

Вот проблема

Мы реализовали URL перенаправления, и я унаследовал код, который читается как это в global.asax, на Sub Application_BeginRequest:

dv.Table = CommonFunctions.ConvertXmlFileToDataSet("/XmlData/WebAppFolders.xml").Tables("Application") 
    dv.RowFilter = "'" + fullOrigionalPath + "' LIKE '%'+ folder + '%'" 
    If dv.Count > 0 Then 'match on key to redirect 
     If fullOrigionalPath.EndsWith(dv(0)("folder") + "/") Then 
      Context.RewritePath(dv(0)("basePage"), True) 
     Else 'missing page in directory --> redirect 
      HttpContext.Current.Items("Raise404") = "true" 
      Response.Redirect("/" + dv(0)("folder")) 
     End If 
     Return 
    End If 

В основном мы читаем большой XML файл, содержащий перенаправления URL-адресов. Это нормально. Проблема происходит в линии ...

HttpContext.Current.Items («Raise404») = «истинный»

В контексте Application_BeginRequest, объект сеанса еще не доступен, так что я не мог использовать он должен хранить флаг, который я назвал Raise404. Вместо этого мне пришлось прибегать к использованию коллекции Items.

Проблема возникает при перенаправлении. Новый жизненный цикл страницы уничтожает массив Items и перезаписывает его новым пустым.

К тому времени, когда я пытаюсь использовать свой флаг Raise404, его больше не существует на моей странице PreRender.

Усложняет дело мы используем мастер-страницы, и поэтому мне было предложено разместить код, который мы хотим выполнить в главной странице

В идеале, если массив Items не разрушалась, этот код будет работать :

Private Sub Page_PreRender(sender As Object, e As System.EventArgs) Handles Me.PreRender 
    If HttpContext.Current.Items("Raise404") IsNot Nothing AndAlso HttpContext.Current.Items("Raise404").Equals("true") Then 
     Response.StatusCode = 404 
     HttpContext.Current.Items("Raise404") = Nothing 
    End If 
End Sub 

Я не уверен, какую переменную я мог бы использовать для хранения моего флага и позволить ему пережить перенаправление.

Любые идеи?

Обновление: проблема заключается в том, что обработчик HTTP, обслуживающий мой запрос, является System.Web.DefaultHTTPHandler, который не реализует IRequiresSessionState, и поэтому, когда мой запрос обрабатывается внутри Global ASAX, сеанс не создается. Таким образом, похоже, что решение будет заключаться в написании пользовательского HTTPHandler, который реализует IRequiresSessionState, и использовать его для всех моих .aspx-файлов. Даже тогда состояние сеанса не создается в Global.ASAX до тех пор, пока не будет поднято PreRequestHandlerExecute. Итак, соединяя все вместе, мне кажется, мне нужно написать собственный обработчик HTTP, который реализует IRequiresSessionState, и задерживает перенаправление страницы до тех пор, пока не будет поднят PreRequestHandlerExecute, где я смогу сохранить свой флаг в состоянии сеанса, и только после этого, перенаправить мою страницу.

Не очень элегантный, и мне интересно, будут ли какие-либо последствия для производительности.

ответ

0

Как я и предполагал, моя проблема была напрямую связана с тем, что IIS 8 избежит использования HTTPHandler, который реализует IRequiresSessionState, если по соображениям производительности он обнаруживает, что объект сеанса не нужен, и поэтому, поскольку код перенаправления происходил во время событие Application_BeginRequest, IIS обрабатывал с этой точки мои запросы, используя System.Web.DefaultHTTPHandler.

Таким образом, при дальнейшем исследовании, я нашел это что было огромная помощь: IRequiresSessionState - how do I use it?

И я также задокументирован себя к этой статье: http://forums.iis.net/t/1094546.aspx

Что решить мою проблема было написать фиктивный класс HttpHandler , Я добавил новый класс к моей папке App_Code:

Imports System.Web 

    Public Class HTTPRequestHandler : Implements IHttpHandler, IRequiresSessionState 

     Private OriginalHandler As IHttpHandler 

     Public Sub New(handler As IHttpHandler) 
      Me.OriginalHandler = handler 
     End Sub 

     Public Sub ProcessRequest(context As HttpContext) Implements IHttpHandler.ProcessRequest 
      Throw New InvalidOperationException("HTTPRequestHandler cannot process requests.") 
     End Sub 

     Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable 
      Get 
       Return True 
      End Get 
     End Property 

     Public ReadOnly Property Handler() As IHttpHandler 
      Get 
       If Me.OriginalHandler IsNot Nothing Then 
        Return Me.OriginalHandler 
       End If 
       Return HttpContext.Current.Handler 
      End Get 
     End Property 
    End Class 

Теперь, во время Application_BeginRequest, сессия не доступна, но HttpContext.Current.Items доступен. Так что, как вторая статья предполагает, во время PostMapRequestHandler я поставил условие:

If HttpContext.Current.Items("Raise404") IsNot Nothing Then 
    Context.Handler = New MyNameSpace.HTTPRequestHandler(Context.Handler) 
End If 

И, наконец, что созданный объект сеанса, который я мог бы, наконец, использовать во время PreRequestHandlerExecute:

HttpContext.Current.Session("Raise404") = "true" 
    Response.Redirect(HttpContext.Current.Items("Redirect")) 

Я определенно не спорю что это не изящно, но он работает, и я могу поднять мою ошибку 404 во время Page_PreRender на моей главной странице.

Надеюсь, это поможет другим.

Cheers.

1

Рассматривали ли вы использование строки запроса для этого?

Response.Redirect("/" & dv(0)("folder") & "?Raise404=true") 

Тогда в вашей мастер-страницы, просто проверить QueryString("Raise404") и действовать соответствующим образом.

Единственный недостаток, который я вижу в том, что злонамеренный клиент может намеренно добавить Raise404=true в строку запроса, что невозможно с текущим решением. Однако я не вижу, как это может навредить.

+0

Да, это пришло в голову, но, к сожалению, у меня есть требование никогда не использовать querystrings :( –

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