重定向后,ASP.NET ScriptManager历史记录url哈希丢失

时间:2012-04-11 14:26:24

标签: asp.net hash history state scriptmanager

我在网上看到几篇帖子抱怨Firefox在重定向后维护了历史记录url哈希..这是我希望的行为 - 它发生在Firefox(11.0),Chrome(18.0)和Opera(11.61)中,但不是IE(9)或Safari(5.1.2)。

在我的页面上,我已经设置并运行了ASP.NET 4.0历史记录点(已经工作了几年)。我还将一些查询字符串传递给页面。我现在要做的是检查新的查询字符串参数的值,如果它与我期望的不匹配,则重定向到具有更新值的同一页面。我正在使用此机制来跟踪浏览器的各个选项卡的会话,以便当它们在多个选项卡中打开相同的页面时,会话值不会从选项卡到选项卡彼此踩踏。

无论如何,我有一切正常工作,包括使用ASP.NET历史记录点的后退/前进 - 当我访问书签并且查询字符串参数不匹配时,我重定向并更改查询字符串参数以跟踪会话,并且然后,使用书签的url中的历史状态将页面重新加载到我想要的状态。但这只适用于Firefox,Chrome和Opera。不是IE对我来说是最重要的(仅基于我们的用户群),而不是Safari。

我已经确定除了(或者可能是因为)url历史状态不存在的事实之外,在IE或Safari中重定向之后不会调用ScriptManager.Navigate。

我可以在ScriptManager上设置一个设置/选项,还是在重定向期间设置/选项以保持历史记录状态?如果历史记录状态在url中,我可以调用ScriptManager。如果需要,直接导航,但网址中不存在值。

如果它有帮助,这里列出了我检查和重定向的位置。然后将ReportRunID附加到需要对每个选项卡唯一的会话变量键。我保留了以前的ReportRunID列表,以便跟踪并清除它们(在一段时间之后,或者遇到超过[MAX] ID的时候),这样我就不会使用这些会话条目使服务器内存过载。

Private Sub Page_PreInit(sender As Object, e As System.EventArgs) Handles Me.PreInit

    If IsPostBack = False Then
        Dim rrid As String = Request.QueryString("RRID")
        If ReportRunIDExists(rrid) = False Then
            ReportRunID = Now.ToString("_HHmmssfff")
            Dim url As String = Request.Url.PathAndQuery

            If String.IsNullOrEmpty(rrid) Then
                Response.Redirect(String.Format("{0}&RRID={1}", url, _reportRunID))
            Else
                Dim idx As Integer = url.IndexOf("&RRID=")
                Response.Redirect(String.Format("{0}&RRID={1}{2}", url.Substring(0, idx), _reportRunID, url.Substring(idx + 6 + rrid.Length)))
            End If
        End If
    End If

End Sub

Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
    'save current RRID/Page/Time to session
    UpdateSessionReportRunID(_reportRunID)
End Sub

...

如果我的书签网址如下:

mysite.com/mypage.aspx?Rpt=123&RRID=_095224678#&&state1=abc&state2=def...

在重定向后的FF / Chrome / Opera中,我的网址如下:

mysite.com/mypage.aspx?Rpt=123&RRID=_102176253#&&state1=abc&state2=def...

但是在重定向后的IE / Safari中,我的网址看起来像是:

mysite.com/mypage.aspx?Rpt=123&RRID=_102176253

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

经过更多的搜索,我发现历史状态哈希不会发送到服务器。它存储在查询字符串中,因此它包含在书签中,但客户端脚本管理器访问它会导致回发加载状态值。由于服务器永远不会在查询字符串中看到哈希值,因此当用户跟随​​该页面的书签时,我无法找到这些值。

这个问题是在我尝试开始逐个跟踪不同浏览器标签的会话状态时引入的。在上面的代码中,如果RRID参数为空或无效,我必须使用新的RRID值重定向到self。当我这样做时,重定向历史状态哈希对于IE和Safari而言是丢失的(但对于其他浏览器则没有。)

我的解决方法:

问题是我需要在我的重定向中包含哈希值,但是这不能从服务器获得,所以我决定向页面注入一些javascript以从客户端执行重定向

我已经有了一个我在不同场景中使用的Client Redirect扩展帮助方法,我修改它以包含当前的哈希值:

<System.Runtime.CompilerServices.Extension()>
Public Sub ClientRedirect(ByVal Response As HttpResponse, ByVal url As String, Optional ByVal target As Target = Nothing, Optional ByVal windowFeatures As String = Nothing, Optional includeCurrentHash As Boolean = False)

    If IsNothing(target) Then
        If windowFeatures = String.Empty Then
            target = ResponseHelper.Target._self
        Else
            target = ResponseHelper.Target._blank
        End If
    End If

    Dim page As Page = CType(HttpContext.Current.Handler, Page)
    url = page.ResolveClientUrl(url)

    Dim script As String
    script = "window.open(""{0}"", ""{1}"", ""{2}"");"

    script = String.Format(script, url & If(includeCurrentHash, "#"" + window.location.hash + """, String.Empty), target.ToString, windowFeatures)
    If target = ResponseHelper.Target._self Then
        'execute after page has loaded
        page.ClientScript.RegisterStartupScript(GetType(Page), "Redirect_" & Now.ToString("HHmmssfff"), script, True)
    Else
        'execute as page is loading
        page.ClientScript.RegisterClientScriptBlock(GetType(Page), "Redirect_" & Now.ToString("HHmmssfff"), script, True)
    End If

End Sub

然后在我执行重定向的Page_PreInit中,我将其更改为执行包含当前哈希的ClientRedirect,并获得了所需的结果:
重定向浏览器,同时在所有浏览器上保留历史状态哈希值。

    'redirect from the client so that we keep the History State URL hash 
    Response.ClientRedirect(String.Format("{0}&RRID={1}", Request.Url.PathAndQuery, _reportRunID), , , True)