我可以使用什么类型的变量?

时间:2015-02-16 14:31:52

标签: asp.net vb.net page-lifecycle

我想要做的事情原则上很简单,但是ASP.NET页面的生命周期给我的一天带来了一桶冷水。

这是问题

我们在Sub Application_BeginRequest上实现了URL重定向和我在Global.ASAX中读取的继承代码:

    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

基本上我们正在阅读包含URL重定向的大型XML文件。这很好。问题发生在行......

HttpContext.Current.Items(" Raise404")=" true"

在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中处理时,没有创建会话。因此,似乎解决方案似乎是编写实现IRequiresSessionState的自定义HTTPHandler,并将其用于我的所有.aspx文件。即使这样,在引发PreRequestHandlerExecute之前,不会在Global.ASAX中创建会话状态。所以,把它放在一起我认为我需要编写一个实现IRequiresSessionState的自定义HTTP处理程序,并延迟页面的重定向,直到引发PreRequestHandlerExecute,我将能够将我的标志存储到Session状态,并且仅在此之后,重定向我的页面。

不是很优雅,我想知道是否会有任何性能影响。

2 个答案:

答案 0 :(得分:1)

您是否考虑过使用查询字符串?

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

然后,在您的母版页中,只需检查QueryString("Raise404")并采取相应行动。

我能看到的唯一缺点是,恶意客户端可以故意Raise404=true添加到查询字符串中,这对于您当前的解决方案是不可能的。但是,我不知道这会有什么坏处。

答案 1 :(得分:0)

正如我所怀疑的,我的问题直接与IIS 8将避免使用实现IRequiresSessionState的HTTPHandler的事实有关,如果出于性能原因它检测到不需要会话对象,因此重定向代码发生在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"))

我绝对不会说这不优雅,但它可以工作,我可以在我的母版页上的Page_PreRender期间提出我的404错误。

我希望这可以帮助别人。

干杯。