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

То, что я пытаюсь сделать, в принципе простое, но жизненный цикл страниц 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, где я смогу сохранить свой флаг в состоянии сеанса, и только после этого, перенаправить мою страницу.

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


person Ajax Ngnurse    schedule 16.02.2015    source источник


Ответы (2)


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

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

Затем на главной странице просто отметьте QueryString("Raise404") и действуйте соответствующим образом.

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

person Heinzi    schedule 16.02.2015
comment
Да, это пришло на ум, но, к сожалению, у меня есть требование никогда не использовать строки запросов :( - person Ajax Ngnurse; 16.02.2015

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

Итак, после дальнейших исследований я обнаружил, что это очень помогло: это?

И я также задокументировал себя в этой статье: 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 на моей мастер-странице.

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

Ваше здоровье.

person Ajax Ngnurse    schedule 16.02.2015