【问题标题】:What type of variable could I use for this?我可以为此使用什么类型的变量?
【发布时间】:2015-02-16 14:31:51
【问题描述】:

原则上我想做的事情很简单,但是 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

基本上,我们正在读取一个包含 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 被引发,在那里我可以将我的标志存储到会话状态中,并且只有在那之后,重定向我的页面。

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    我能看到的唯一缺点是恶意客户端可以故意Raise404=true 添加到查询字符串中,这在您当前的解决方案中是不可能的。但是,我看不出这会造成什么伤害。

    【讨论】:

    • 是的,我想到了,但不幸的是我要求永远不要使用查询字符串:(
    【解决方案2】:

    正如我所怀疑的,我的问题与以下事实直接相关: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 错误。

    我希望这对其他人有帮助。

    干杯。

    【讨论】:

      猜你喜欢
      • 2015-03-23
      • 2016-11-27
      • 1970-01-01
      • 2020-05-16
      • 2016-05-16
      • 2017-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多