跨网页公布(Cross-Page Posting)
跨网页公布时.Net2.0的新机制,这个机制可以让您在设计网页导航程序的时候获取更大
的弹性,不但功能更为丰富,且使用也十分容易,有别于传统的程序技巧,令人眼睛为之一亮.
首先来比较下网页导航技术:
● HyperLink
● Response.Redirect()
● Server.Transfer()
● 跨网页公布(Cross-Page Posting)
前三种方式原本.net 1.0 就具有滴,而让人感到新鲜的是” 跨网页公布”,下面将上面4种技术
的特性作一个简介表.
网页导航技术特性 | ||
导航方式 | 特性 | 使用方式 |
HyperLink
| 1. 在目标网页上执行新要求 2. 不要将目前的网页信息传递至目标网页 3. 需要用户启动 4. 可重新导向任何网页,而不只是同一个Web应用程序中的网页 5. 可让您使用查询字符串或工作阶段状态,共享网页之间的信息(HyperLink控件可让您以程序设计方式建立URL和查询字符串) | 1. 导航而没有额外处理(如连接的菜单或清单中) 2. 应该有用户控制另外一个网页的导航时 |
Response.Redirect()
| 1. 将目前的网页信息公布至目标网页 2. 公布目标网页的可用信息 3. 需要用户启动 4. 可重新导向至任何网页,而不只是同一个Web应用程序中的网页 5. 允许目标网页在目标网页和来源网页位于相同的Web应用程序时,读取来源网页的公用属性 | 1. 将目前网页信息传递至目标网页(多页窗体) 2. 应该有用户控制导航时 |
Server.Transfer()
| 1. 在目标网页上执行要求 2. 将查询字符串传递给目标网页 3. 以程序设计和动态方式,控制目标URL和查询字符串 4. 可让您重新导向任何网页,而不只是同一个Web应用程序中的网页 5. 可让您重新导向之前储存处于工作阶段状态之来源网页信息,以便与目标网页共享信息 | 1.若为条件式导航,则在想要控制目标URL和发生导航时才使用,例如,如果应用程序必须根据用户提供的资料判断所要导航的网页,请使用此选项 |
跨网页公布
| 1. 将控件传输至呈现的新网页(取代来源网页) 2. 只要新导向至与来源网页位于相同的Web应用程序的目标网页 3. 可让您从来源网页读取值和公用属性 4. 不要目标网页的信息更新浏览器信息,按浏览器中的[重新整理]或[上一步]按钮会造成无法预期的行为 | 1. 若为条件式导航,则在想要控制导航的发生时机及访问来源网页内容时使用 2. 此选项最适合在用户看不到URL的情况下使用 |
看上面的文子很枯燥,看例子:
HyperLink
<asp:HyperLink ID="HyperLink1" runat="server" BackColor="#3399FF"
BorderColor="#FF3399" BorderStyle="Solid" BorderWidth="1px" ForeColor="#996633"
NavigateUrl="~/Public/Login.aspx" Target="_blank">HyperLink导航</asp:HyperLink>
当然你也可以动态生成HyperLink:
protected void Page_Load(object sender, EventArgs e)
{
HyperLink hl = new HyperLink();
hl.ID = "HyperLink2";
hl.Text = "HyperLink导航二";
hl.NavigateUrl = "~/Public/Login.aspx";
hl.ForeColor = System.Drawing.Color.FromName("#996633");
hl.BackColor = System.Drawing.Color.FromName("#3399FF");
hl.BorderColor = System.Drawing.Color.FromName("#FF3399");
//hl.BorderStyle=BorderStyle.Solid;
hl.BorderWidth = Unit.Pixel(1);
hl.BorderWidth = Unit.Parse("1px");
hl.Target="_blank";
Page.Controls.Add(hl);
}
Response.Redirect()
/**
HttpResponse 类实现了 Redirect 方法的两个重载版本。 第一个重载方法仅有一个输入参数,该参数就是目标位置的 URL。此版本定义如下: public void Redirect(string url);
第二个重载方法有两个输入参数: 目标位置的 URL,和一个指示是否停止运行当前页的布尔值。 此版本定义如下: public void Redirect(string url, bool endResponse);
当您使用第一个重载版本时,会在内部调用第二个重载版本,并会向其第二个输入参数传递一个布尔值 True。
endResponse True时:对Response.End 的内部调用,终止跳转页以后的所有操作。即执行Exit sub/function等等
endResponse False时:取消对 Response.End 的内部调用,将执行 Response.Redirect 后面的代码.
**/
Response.Redirect("~/Public/Login.aspx");
//Response.Redirect("~/Public/Login.aspx",false);
Server.Transfer()
/**
Server.Transfer(),它对于当前请求,终止当前页的执行,并使用指向一个新页的指定 URL 路径来开始执行此新页。
但是新页执行过后,当前页面的地址栏中虽然仍然是原来的地址,但内容已经是新的页面的内容了,地址栏的地址只能称为”伪地址",当前的真正地址已经是新页面的地址了。
提个建议:不要轻易使用这个东东,Server.Transfer()执行的时候不去验证新的页面的授权,也就是说,当前用户只要有权访问当前页面,它并不去验证对新页面是否有权限访问,
直接执行新的页面。所以当涉及到权限问题时,一定要注意哦
* */
Server.Transfer("~/Public/Login.aspx");
好了,言归正传吧,到了跨网页公布:
跨网页公布必须依附在Button按钮的PostBackUrl属性之上,并且由用户触发,而Button按钮只支持Button,LinkButton,ImageButton这三种类型,html代码:
<asp:Button ID="btnSummit" runat="server" Text="Button"
PostBackUrl="~/Public/Login.aspx" />
或者用Code-Behind代码:
protected void Page_Load(object sender, EventArgs e)
{
btnSummit.PostBackUrl = "~/Public/Login.aspx";
}
例1:访问来源网页的控件
a.aspx html代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="a.aspx.cs" Inherits="Public_a" %>
<!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>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
名字:<asp:TextBox ID="TxtName" runat="server"></asp:TextBox>
<br />
<br />
年龄:<asp:TextBox ID="TxtAge" runat="server"></asp:TextBox>
<br />
<br />
<asp:Button ID="btnSummit" runat="server" Text="确定"
PostBackUrl="b.aspx" />
</div>
</form>
</body>
</html>
b.aspx.cs代码:
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class Public_b : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
/**
* 由于来源网页的控件默认是被保护的,也就是在另一个网页不能直接访问它,必需通过PreviousPage的FindControl()方法来取得来源网页的"控件",
* 这里是控件而非以往的单只是参数,意思是该控件的所有属性都能访问。
*
* PreviousPage本身属于Page类型,并只有在来源网页和目标网页属于相同的Asp.Net应用程序中,目标网页的PreviousPage属性才会包含来源网页的
* 引用:如果网页不是跨网页公布的目标,或是网页在不同的应用程序中,就不会初始化PreviousPage属性,也就是不能使用PreviousPage来存取任何
* 信息.
*
* */
TextBox strName = (TextBox)PreviousPage.FindControl("TxtName");
TextBox strAge = (TextBox)PreviousPage.FindControl("TxtAge");
string strRs = "您输入的名字是:" + strName.Text + ",您的年龄是:" + strAge.Text;
LblResult.Text = strRs;
}
}
分别输入:忍者为王,22后点击按钮输出:
您输入的名字是:忍者为王,您的年龄是:22
例2:访问来源网页的属性
方法一:@PreviousPageType指示符
a.aspx html代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="a.aspx.cs" Inherits="Public_a" %>
<!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>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
名字:<asp:TextBox ID="TxtName" runat="server"></asp:TextBox>
<br />
<br />
年龄:<asp:TextBox ID="TxtAge" runat="server"></asp:TextBox>
<br />
<br />
<asp:Button ID="btnSummit" runat="server" Text="确定"
PostBackUrl="b.aspx" onclick="btnSummit_Click" />
</div>
</form>
</body>
</html>
a.aspx.cs代码:
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class Public_a : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
//定义属性分别对名字和年龄进行操作
private string name;
private string age;
public string Name
{
set
{
name = value;
}
get
{
return name;
}
}
public string Age
{
set
{
age = value;
}
get
{
return age;
}
}
protected void btnSummit_Click(object sender, EventArgs e)
{
Name = TxtName.Text;
Age = TxtAge.Text;
}
}
b.aspx html代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="b.aspx.cs" Inherits="Public_b" %>
<!--
添加PreviousPageType指示符:
使用@PreviousPageType指示符表面上和直接访问来源网页中控件信息是差不多的,但是在安全的防护上有很大的差距,@PreviousPageType指示符可以
进一步限制目标网页所能够访问来源网页的默认公开的信息,对于预防潜在恶意用户限制只能访问特定信息而非Page中的所有控件,因此更具有安全性。
一个网页Page中只能有一个@PreviousPageType指示符,否则编译会产生报错信息。
-->
<%@ PreviousPageType VirtualPath="~/Public/a.aspx" %>
<!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>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
<asp:Label ID="LblResult" runat="server" Text="Label"></asp:Label>
</form>
</body>
</html>
b.aspx.cs代码:
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class Public_b : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
LblResult.Text = "你输入的名字是:" + PreviousPage.Name + ",您输入的年龄是" + PreviousPage.Age;
}
}
分别输入:忍者为王,22后点击按钮输出:
你输入的名字是:忍者为王,您输入的年龄是22
方法二:@Reference指示符
a.aspx html代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="a.aspx.cs" Inherits="Public_a" %>
<!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>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
名字:<asp:TextBox ID="TxtName" runat="server"></asp:TextBox>
<br />
<br />
年龄:<asp:TextBox ID="TxtAge" runat="server"></asp:TextBox>
<br />
<br />
<asp:Button ID="btnSummit" runat="server" Text="确定"
PostBackUrl="b.aspx" onclick="btnSummit_Click" />
</div>
</form>
</body>
</html>
a.aspx.cs 代码:
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class Public_a : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
//定义属性分别对名字和年龄进行操作
private string name;
private string age;
public string Name
{
set
{
name = value;
}
get
{
return name;
}
}
public string Age
{
set
{
age = value;
}
get
{
return age;
}
}
protected void btnSummit_Click(object sender, EventArgs e)
{
Name = TxtName.Text;
Age = TxtAge.Text;
}
}
b.aspx html代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="b.aspx.cs" Inherits="Public_b" %>
<!--
添加Reference指示符:
使用@Reference指示符将PreviousPage转换成与来源网页相同的类型,具有强类型的特性,而强类型的好处是可以通过Intellisense来直接访问,这是它
最大的不同点.
-->
<%@ Reference VirtualPath="~/Public/a.aspx" %>
<!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>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
<asp:Label ID="LblResult" runat="server" Text="Label"></asp:Label>
</form>
</body>
</html>
b.aspx.cs 代码:
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class Public_b : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//将PreviousPage转换与来源网页相同类型
Public_a sourcePage = (Public_a)PreviousPage;
LblResult.Text = "你输入的名字是:" + sourcePage.Name + ",您输入的年龄是" + sourcePage.Age;
}
}
分别输入:忍者为王,22后点击按钮输出:
你输入的名字是:忍者为王,您输入的年龄是22
@PreviousPageType指示符和@Reference指示符作用差不多,但@Reference指示符是通过强类型的方式进行访问的,@Reference指示符可以有多个。如:
<%@ Reference VirtualPath="~/Public/a.aspx" %>
<%@ Reference VirtualPath="~/Public/Login.aspx" %>
且生成编译不会产生错误,但在所有引用到的来源网页其Button都要声明PostBackUrl属性指定同一个目标网页,且目标网页的Code-Behind程序必须添加额外的判断与防呆程序代码,否则程序同时访问2个以上的来源网页,网页执行时会发生错误,你可以用如下的程序代码:
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (PreviousPage != null)
{
if (PreviousPage.IsCrossPagePostBack)
{
Public_a sourcePage = (Public_a)PreviousPage;
LblResult.Text = sourcePage.Name + "<br>" + sourcePage.Age;
}
}
}
catch (Exception ex)
{
Response.Write(ex.Message.ToString());
Response.End();
}
try
{
if (PreviousPage != null)
{
if (PreviousPage.IsCrossPagePostBack)
{
Public_Login pl = (Public_Login)PreviousPage;
LblResult.Text = pl.Name + "<br>" + pl.Age;
}
}
}
catch (Exception ex)
{
Response.Write(ex.Message.ToString());
Response.End();
}
}
通过PreviousPage.IsCrossPagePostBack可以防止异常发生,保障代码的完整性。在目标网页如果不加判断,假如从任意一个不属于来源网页导向目标网页时,PreviousPage对象就会null,就会引发异常。
最后来了解下跨网页公布原理:
1. 来源网页跨网页公布到目标网页是通过Button的PostBackUrl属性指定目标网页,由用户来触发。
2. 目标网页将来源网页的ViewState另外存储一份后,随即来源网页的ViewState所存储的专题会被废弃掉。
3. 当在目标网页使用到PreviousPage对象时,系统会自动初始化与来源网页同一类型的Page(PreviousPage),并且在目标网页的Load_complete阶段将原先所存储保留下来的ViewState还原到PreviousPage。
4. 而PreviousPage表示一个与来源网页相同的新生的实体,并且注入了原先所保存的ViewState状态。