zoukankan      html  css  js  c++  java
  • ASP.NET 状态管理(查询字符串 和 跨页回发)

           视图状态一个最大的限制是它必须和特定页面紧密绑定。当用户从一个页面浏览到另一个页面时,这些信息也就消失了。这个问题有几种解决方案,最佳的方案取决于你的项目需求。

    查询字符串

           一个常用的办法是在 URL 中使用查询字符串传送信息。搜索引擎中频繁的使用了这种办法。

    http://www.google.ca/search?q=organic+gardening

           查询字符串的优势:

              它是轻量级的,并且不会加重服务器的负担。和跨页回发不同,查询字符串很容易在页面间传送相同的信息

           查询字符串的限制:

    1. 信息仅限于简单的字符串,只能包含合法的 URL 字符
    2. 用户很容易看到信息,对因特网上的窃听者也是如此。
    3. 大胆的用户可能会修改查询字符串或给它赋新值,而你的程序并不能预期和预防这些修改。
    4. 多数浏览器对 URL 字符串的长度有限制(通常 1K-2K)

           尽管如此,把信息加入到查询字符串中仍是一项很有用的技术

    使用查询字符串

           没有基于集合的方式来帮助你放置信息,你需要自己放置查询字符串的存储信息。

    int recordID = 10;

    Response.Redirect("newpage.aspx?recordID=" + recordID.ToString());

    可以发送多个参数,中间用符号 & 隔开

           接收页面很容易就可以使用查询字符串来工作,它使用内置的 Request 对象提供的 QueryString 字典集合来取值:

    string ID = Requet.QueryString["recordID"];

    如果集合中不包含查询的 Key 值,那么 ID 将被设为 null 值

    取得的值总是字符串,也因此很容易就可以转换为其它数据类型。

    URL 编码

           查询字符串的一个潜在问题是使用 URL 中不允许的字符(URL 中所有字符必须是字母、数字、及少量的符号"$ - . + ! * ' ( ) , ")。如果担心将要在查询字符串中保存的数据含有非法字符,可以使用 HttpServerUtility 类中提供的方法进行编码。

    string productName = "Flying Carpet";

    Response.Redirect("newpage.aspx?productName=" + Server.UrlEncode(productName));

    可以使用 Server.UrlDecode() 方法将字符串恢复其初始值,但不需要这么做,当使用 Request.QueryString集合时,ASP.NET 自动解码了该值。

    跨页回发

           只不过是把信息从一个页面发送到另一个页面去,这个技术听起来很简单,但却是一个潜在的雷区!使用的不好,会导致创建的页面紧密耦合而难于改进和调试。

           支持跨页回发的基础架构是属性 PostBackUrl,它在 IButtonControl 接口中定义并在按钮类控件(Button、LinkButton、ImageButton)中出现。只需要简单地将 PostBackUrl 设置为其他 Web 窗体的名字就可以使用跨页回发了。

           看下面的小示例:

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="CrossPage1.aspx.cs" Inherits="Chapter06_CrossPage1" %>
     
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>CrossPage1</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>    
            <asp:TextBox ID="txtFirstName" runat="server"></asp:TextBox>
    &nbsp;<asp:TextBox ID="txtLastName" runat="server"></asp:TextBox>
    &nbsp;<asp:Button ID="btnSubmit" runat="server" PostBackUrl="CrossPage2.aspx" 
                Text="Submit" /> 
        </div>
        </form>
    </body>
    </html>

    CrossPage2.aspx 可以通过 PreviousPage 属性和 CrossPage1.aspx 中的对象进行交互:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (Page.PreviousPage != null)
        {
            lblInfo.Text = "You came from a page titled " + PreviousPage.Header.Title;
        }
    }

    1. 获取页面特定信息

           在先前的示例中,仅仅是获得了 Page 类的成员。如果要得到更具体的细节,如控件的值,必须把 PreviousPage 转换为适当的类型:

    protected void Page_Load(object sender, EventArgs e)
    {
        Chapter06_CrossPage1 prePage = PreviousPage as Chapter06_CrossPage1;
        if (prePage != null)
        {
            // (Read some infomation from previous page.)
        }        
    }

    注:

           对于没有项目文件的网站,VS 会标记为错误,表示它没有源页面类的类型信息(如 CrossPage1),不过编译后这个错误会消失

           即便已经将前一页面转换成了正确的页面类型,但还是不能够直接访问控件的值。这是因为控件被声明为了受保护的成员,此时,可以通过在页面类中添加封装控件变量的属性来实现上述操作:

    public TextBox FirstNameTextBox
    {
        get { return txtFirstName; }
    }
     
    public TextBox LastNameTextBox
    {
        get { return txtLastName; }
    }

           但这不是好的方式,它显示了太多的细节,还允许目标页面随意访问控件的任意属性!最好的方式是定义特定且有效的方法或属性来提取需要的信息:

    public string FullName
    {
        get { return txtFirstName.Text + txtLastName.Text; }
    }

           现在已经达到最好的状态了。两个页面的关系被文档化且易于理解。即使源页面控件改变了,仍只需要修改 FullName 属性,修改仅限于 CrossPage1.aspx 页面,而完全不需要修改 CrossPage2.aspx 页面

    2. 在任意事件处理程序中进行跨页发送

           除了使用实现了 IButtonControl 接口的那些按钮进行跨页发送外,我们还可以使用一个重载的 Server.Transfer()方法将试图状态信息完整的送到目标页面。只要简单的加上一个值为 true 的 oreserverFrom 参数即可。

    // 为 true,则保留 System.Web.HttpRequest.QueryString 和 System.Web.HttpRequest.Form 集合。
    // 为 false,则清除 System.Web.HttpRequest.QueryString 和 System.Web.HttpRequest.Form 集合。
    Server.Transfer("CrossPage2.aspx", true);

           这样就可以在网页代码的任意地方使用跨页发送了(只要能访问到 Server 对象的地方)。

           该技术会造成服务器的重定向,这意味着没有额外的往返来重定向客户,即使已去了另一个页面,但客户端浏览器中的URL不会改变。

           怎么区分是通过一个按钮跨页传送还是通过 Server.Transfer()方法跨页传送的呢?

    protected void Page_Load(object sender, EventArgs e)
    {
        if (PreviousPage == null)
        {
            // 直接被 get 或 post 方式请求
        }
        else if (PreviousPage.IsCrossPagePostBack)
        {
            // 通过 Button 类跨页回传
        }
        else
        {
            // 通过 Server.Transfer() 跨页回传
        }
    }

    3.   IsPostBack 属性和 IsCrossPagePostBack 属性

           理解 Page.IsPostBack 属性在跨页回送中是很重要的。源页面(触发了跨页回送的页面)的 IsPostBack 属性为 true。目的页面(接收跨页回送的页面)的 IsPostBack 属性为 false。这个系统的好处是,它意味着你的初始化代码通常会在该运行的时候运行

           假设第一次请求 CrossPage1.aspx 使用如下代码时,它执行了一些费时的初始化工作:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            // Retrieve some data from a database and display it on the page.
        }
    }

           现在假设用户通过跨页回送从 页面1 转到了 页面2 。只要 CrossPage2.aspx 方位 PreviousPage 属性,就会执行 CrossPage1.aspx 页面生命周期。此时,再次触发 CrossPage1.aspx 的 Page.Load 事件。然而,CrossPage1.aspx 上的 Page.IsPostBack 属性为 true,你的代码就会跳过费时的初始化步骤,控件的值从视图状态得以恢复。另一方面,CrossPage2.aspx 的IsPostBack 属性为 false,所有该页面执行必要的第一次初始化。

           在某些情况下,当页面不是跨页回送的源页面时,你可能会有用于处理第一次请求和所有接下来的回送的代码。在这种情况下,你可以查看 IsCrossPagePostBack 属性,如果当前页面触发了一个跨页回送,则该属性的值为 true。

    protected void Page_Load(object sender, EventArgs e)
    {
        if (Page.IsCrossPagePostBack)
        {
            // This page triggered a postback to CrossPage2.aspx.
        }
        else if (Page.IsPostBack)
        {
            // This page was posted back normally.
            // Don't do the first-request initialization.
        }
        else
        {
            // This is the first request for the page.
            // Perform all the required initialization.
        }
    }

    4. 跨页发送和验证

           在跨页回送中使用验证有一些潜在的麻烦。如果源页面包含验证控件,那么使用跨页发送会发生什么呢?

    image

           两个按钮都将 CausesValidation 设置为 true,因此单击任何一个按钮来触发跨页回发,回发都会被浏览器的客户端验证阻止,并出现错误信息。此时将 RequiredFieldValidator 验证控件的属性 EnableClientScript 设为 false 以模拟客户端不支持 JavaScript 脚本或恶意客户避开了客户端验证,再次单击任一按钮,页面回发,此时新页面出现了。

           为了避免发生这种问题,显然,在执行任意动作前必须检查 Page.IsValid 以在目标页面中保证源页面有效。这是需要验证的 Web 窗体的标准防范。不同的是,当页面无效时什么都不做事不够的,我们往往需要采用一些步骤将用户带回到原始页面

    // This code is in target page.
    protected void Page_Load(object sender, EventArgs e)
    {
        if (PreviousPage != null)
        {
            if (!PreviousPage.IsValid)
            {
                // Display an error message or just do nothing.
                // Response.Redirect("CrossPage1.aspx");
            }
            else
            {
                // ...
            }
        }
    }

           上面这段代码还可以再度改进。现在,因为页面是被重新请求的(不是回发),所有当用户回到原始页面时,错误信息不回出现。要修正这个问题,可以设置一个标记让原始页面知道,请求已被目标页面拒绝。

    protected void Page_Load(object sender, EventArgs e)
    {
        if (PreviousPage != null)
        {
            if (!PreviousPage.IsValid)
            {
                // UrlReferrer: 获取有关客户端上次请求的 URL 的信息(包含许多信息)
                // AbsolutePath: 获取 URI 的绝对路径
                Response.Redirect(Request.UrlReferrer.AbsolutePath+"?err=true");
            }
            else
            {
                // ...
            }
        }    
    }

           现在,原始页面只需要检查查询字符串中的标记并再次执行验证,验证将显示无效数据的信息。

    protected void Page_Load(object sender, EventArgs e)
    {
        if (Request.QueryString["err"]!=null)
        {
            Page.Validate();
        }
    }

           还可以做更多来改进页面。比如说,用户已经填写了某一详细表单的一部分,这时候再重新请求页面就不太好,因为这样就清空了用户的输入,用户将不得不重新开始。你应该在响应流中写一些 JavaScript 代码,它使用浏览器的回退功能回到源页面。

           这个示例演示了跨页回发通常要比开发人员想象的麻烦。如果没有小心处理,跨页回发会导致生成紧耦合的页面,它们相互有依赖性,这使得它们将来的修改变得困难。

  • 相关阅读:
    idea 界面乱码问题 file was loaded in the wrong enconding:"utf-8"
    svn 下载,安装,创建库,设置用户和用户组,赋权限
    eclipse文件中的乱码问题
    Eclipse安装Spring插件springsource-tool-suite
    vue.js2.0:搭建开发环境及构建项目
    排序List集合中的元素
    Java GC机制和对象Finalize方法的一点总结
    xfire发布的Webservice中Spring注入为空的解决方案
    Http报文格式学习及Get和Post主要区别总结
    [转] tomcat组成及工作原理
  • 原文地址:https://www.cnblogs.com/SkySoot/p/2588523.html
Copyright © 2011-2022 走看看