【问题标题】:Passing Objects via QueryString通过 QueryString 传递对象
【发布时间】:2008-10-01 13:11:00
【问题描述】:

我有对象 A,而对象 A 又具有对象 B 类型的属性

Class A

property x as Object B

End Class

在我的 ASP.NET 页面上,当我选择一个映射到 A 类型对象的 gridview 项时,我将该对象序列化到 QueryString 上并将其传递到下一页。

但是,如果属性 x 实际上具有某些值,我会遇到问题,因为它看起来超出了 4k 的 QueryString 容量长度(尽管我认为对象没有那么大)

我已经考虑过以下方法来做到这一点

  • 会话变量

未使用的方法,因为我已经读到这是不好的做法。

  • 使用对象的唯一键并在下一页检索它。

不使用方法,因为对象不映射到表中的单个实例,它们由来自不同数据库的数据组成。

所以我想我的问题有两个方面

  • 是否值得使用 GKZip 进一步压缩查询字符串(这可能吗??)
  • 人们会建议使用哪些其他方法来执行此操作?

【问题讨论】:

    标签: asp.net vb.net


    【解决方案1】:

    如果在浏览器中显示下一页的 url 无关紧要,您可以使用 context.items 集合。

    context.items.add("keyA", objectA)
    server.transfer("nextPage.aspx")
    

    然后在下一页:

    public sub page_load(...)
        dim objectA as A = ctype(context.items("keyA"), objectA)
        dim objectB as B = objectA.B
    end sub
    

    使用它的一个原因是,如果您希望用户相信下一页确实是第一页的一部分。对他们来说,似乎只是发生了 PostBack。

    此外,如果使用“下一页”的唯一方法是您首先来自“第一页”,那么您实际上并不需要使用这种方法的唯一键。上下文项集合的范围仅针对此特定请求。

    我同意其他发帖人的观点,他们提到查询字符串上的序列化对象比使用会话状态更糟糕。如果您确实使用会话状态,请记住在使用后立即清除您使用的密钥。

    【讨论】:

      【解决方案2】:

      我不明白你为什么不使用会话状态但是......

      选项 1:视图状态

      选项2:表单参数而不是查询字符串

      但也请注意,当您序列化/反序列化时,您不会得到相同的对象。您将获得一个新对象,该对象使用已序列化的原始值进行初始化。你最终会得到两个对象。

      编辑:您可以使用与会话状态相同的语法将值存储在视图状态中

      ViewState["key"] = val;

      该值必须是可序列化的。

      【讨论】:

      • 我不确定他将如何在这个问题中使用视图状态。
      • 您可以在其中存储对象。 Viewstate["Object_key"] = val;
      • 不,这就是为什么我一开始就说我不明白不使用会话状态......但是,这是一个选项。
      【解决方案3】:

      虽然在会话中存储对象可能被认为是不好的做法,但它比通过序列化查询字符串传递它们要好很多光年。

      回到经典的 asp 中,在会话中存储对象被认为是不好的做法,因为您创建了线程关联性,并且您还通过添加其他 Web 服务器限制了扩展站点的能力。这不再是 asp.net 的问题(只要您使用外部状态服务器)。

      还有其他原因可以避免使用会话变量,但在您的情况下,我认为这是可行的方法。

      另一种选择是将需要访问此对象的 2 个页面合并为一个页面,使用面板隐藏和显示所需的“子页面”并使用视图状态来存储对象。

      【讨论】:

        【解决方案4】:

        我不认为在查询字符串中传递它,或者将它存储在会话中,是一个好主意。

        您需要以下之一:

        a) 一个缓存层。像 Microsoft Velocity 这样的东西会起作用,但我怀疑你是否需要那种规模的东西。

        b) 将您需要的数据库中每个对象的键放入查询字符串中,并在下次检索它们。 (例如 myurl.com/mypage.aspx?db1objectkey=123&db2objectkey=345&db3objectkey=456)

        【讨论】:

          【解决方案5】:

          使用会话状态似乎是最实用的方法,这正是它的设计目的。

          【讨论】:

            【解决方案6】:

            缓存可能也不是这里的答案。正如 Telos 所说,我不确定你为什么不考虑会话。

            如果您有一个依赖于可用数据的页面,那么您只需在页面加载中抛出一个保护子句...

            public void Page_Load()
            {
            
                if(!IsPostBack)
                {   
                    const string key = "FunkyObject";
                    if(Session[key] == null)
                        Response.Redirect("firstStep.aspx");
            
                    var obj = (FunkyObject)Session[key];
                    DoSomething(obj);
                }
            }
            

            如果 session 完全不在问题范围内,那么您将不得不在另一个页面上重新实现该对象。只需在查询字符串中发送唯一标识符,以便您可以再次将其拉回。

            【讨论】:

              【解决方案7】:

              会话并不总是可用的。例如,当 IE 上的 XSS(跨站点脚本)安全设置阻止存储第三方 cookie 时。如果您的站点是在 IFrame 中从不是您的 DNS 域的站点调用的,则默认情况下您的 cookie 将被阻止。没有 cookie = 没有会话。

              另一个例子是您必须将控制权传递给另一个网站,该网站会将您的网站作为纯 URL 而不是帖子进行回调。在这种情况下,您必须将会话参数存储在查询字符串参数中,考虑到 4k 大小限制和 URL 编码,更不用说加密等,这很难做到。

              问题是大多数内置序列化方法都非常冗长,因此不得不求助于自己滚动的方法,可能使用反射。

              不使用会话的另一个原因仅仅是为了提供更好的用户体验;会话在 N 分钟后和服务器重新启动时被清除。好的,在这种情况下,视图状态更可取,但有时无法使用表单。好的,可以依靠 JavaScript 进行回发,但同样,这并不总是可行的。

              这些是我目前正在编码的问题。

              【讨论】:

                【解决方案8】:

                这是我的工作:

                Page1.aspx - 添加我的对象实例的公共属性。添加一个按钮 (Button1),并将 PostBackURL 属性设置为 ~/Page2.aspx

                Private _RP as ReportParameters
                Public ReadOnly Property ReportParams() as ReportParameters
                  Get
                    Return _RP
                  End Get
                End Property
                
                Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
                  _RP = New ReportParameters       
                  _RP.Name = "Report 1"
                  _RP.Param = "42"    
                End Sub
                

                现在,在第二个页面上,Page2.aspx 在第一个指令下页面顶部的标记中添加以下内容:

                <%@ PreviousPageType VirtualPath="~/Default.aspx" %>
                

                然后对于Page2.aspx后面代码中的Page_Load,添加如下

                If Not Page.PreviousPage is Nothing Then
                  Response.write (PreviousPage.ReportParams.Name & " " & PreviousPage.ReportParams.Param)
                End If
                

                【讨论】:

                  【解决方案9】:

                  面对类似的情况,我所做的是将 XML 序列化对象并将其作为查询字符串参数传递。这种方法的困难在于,尽管进行了编码,但接收表单会抛出异常,说“潜在危险的请求......”。我解决的方法是加密序列化对象,然后编码以将其作为查询字符串参数传递。这反过来又使查询字符串防篡改(奖金进入 HMAC 领域)!

                  FormA XML 序列化一个对象 > 加密序列化字符串 > 编码 > 作为查询字符串传递给 FormB FormB 解密查询参数值(因为 request.querystring 也解码) > 使用 XmlSerializer 将生成的 XML 字符串反序列化为对象。

                  我可以根据要求分享我的 VB.NET 代码到 howIdidit-at-applecart-dot-net

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2013-03-28
                    • 2023-03-30
                    • 2017-09-11
                    • 2018-04-20
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-11-24
                    相关资源
                    最近更新 更多