好的,所以这是标准的公平。您有一个应用程序,用户可能会说搜索酒店或其他任何内容。你显示一个网格。
用户选择一个值。现在是时候计算出那个客户、那个项目、那个订单或者其他什么的细节了。平面简数据库的东西 - 每天都做。
那么,虽然网络概念是无状态的? (与桌面不同,您的代码值保持不变?
在网络领域,每个页面都回传,您的代码每次都从头开始!
因此,在每个 Web 请求上都会创建一个页面类的“新”实例。 (除非您对 Web 方法使用 ajax 调用 - 但是当您这样做时,您的代码不能触摸也不能查看任何控件值 - 因为在该页面回发发生之前它们不存在。
好的,那么你现在的设计模式是什么?
毕竟,就像任何应用程序一样,您可以单击一行,然后显示详细信息或跳转到另一个页面以说编辑该选择。
这里有几种方法。
首先,还是很常见?
您在 url 中传递值。事实上,在输入这篇文章时,我可以在 URL 中看到堆栈溢出代码使用的“消息”编号(值)。
你仍然会看到亚马逊或其他服务的网址中经常有很多“东西”。
www.mywebsite.com?&ID=134&Account=5454444
因此,您可以使用 URL 参数(通常称为查询字符串值)将值传递给下一个 Web 表单购买。现在这种方法的问题是什么?好吧,对于某些东西,比如数据库 PK 值,甚至是信用卡号?您不希望该信息暴露给用户。更糟糕的是,用户可以“乱用”并修改这些值。
现在,对于一般网站,假设我们想要一个城市的人口?
www.mywebsite.com/ShowPopulation.aspx?City="New约克"
在上面,效果很好,因为最终用户甚至可以更改该值。
而且一些大型网站仍然使用这种方法,因为它在服务器端的成本为零(因此为了获得巨大的可扩展性,这种选择是可行的)。
但是,今天,我们有了更好的选择,我非常不喜欢那些乱七八糟的 URL。它们可能会带来安全问题。
因此,您可以将行点击“ID”传递给 URL 中的下一个表单。
下一个?
视图状态:
ViewState 是每页的。并且不会暴露于 URL。因此这是一个很好的选择,我将结合为什么这个选择通常比下一个选择好得多。
会话:
嗯,这个真的很漂亮。它允许您将变量推入 session(),并且它们在应用程序范围内保持每个用户!!!
但是,你要小心使用 session() 而不加考虑!!!
假设我们有一个您要预订的酒店网格。
因此,您可以使用 session() 将此酒店“ID”传递给下一个表单。
但是,如果同一用户启动另一个浏览器页面并选择了不同的酒店,然后跳转到酒店预订页面,会发生什么情况。如果我们将酒店 ID 存储在 session() 中?
该用户的应用范围很广!!!因此,现在在酒店预订中打开了两个网页,我们将在会话中获得错误的 pk id。如果你说要买房呢?那么要么你不允许一个用户打开一个以上的购房页面,要么你只使用会话来传递值。
所以,我所做的是使用 session() 将值传递给下一个表单,然后立即将传递的值移动到 ViewState。 (因为视图状态是每页)。
所以,让我们填充一个网格,从网格中选择一家酒店,然后跳转到下一页。
所以说我们有这个:
<div style="width:50%;margin-left:25px;margin-top:25px">
<asp:GridView ID="MyGrid" runat="server" CssClass="table table-hover"
DataKeyNames="ID" AutoGenerateColumns="false" OnRowDataBound="MyGrid_RowDataBound" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
<asp:BoundField DataField="HotelName" HeaderText="Hotel Name" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Province" HeaderText="Province" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:CheckBoxField DataField="Active" HeaderText="Active" ItemStyle-HorizontalAlign="Center" />
<asp:TemplateField >
<ItemTemplate>
<asp:Button ID="cmdHotelSel" runat="server" Text="View Hotel"
OnClick="cmdHotelSel_Click"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
我们在代码中加载网格:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
LoadGrid();
}
public void LoadGrid()
{
using (SqlCommand cmdSQL =
new SqlCommand("SELECT * FROM tblHotels ORDER by HotelName ",
new SqlConnection(Properties.Settings.Default.TEST3)))
{
cmdSQL.Connection.Open();
MyGrid.DataSource = cmdSQL.ExecuteReader();
MyGrid.DataBind();
}
}
好的,我们现在有了这个:
好的,让我们使用 Session 将行点击传递到下一页
(比如显示酒店信息的详细信息表格)。
所以,按钮点击代码可以是这个(获取PK行id)
protected void cmdHotelSel_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
GridViewRow gRow = (GridViewRow)btn.Parent.Parent;
int PK = (int)MyGrid.DataKeys[gRow.RowIndex]["ID"];
Session["HotelPK"] = PK;
Response.Redirect("ViewHotel.aspx");
}
所以,我们将 PK id 推入 session()。 (会话 = 全局 = 每个用户)
所以,现在在目标页面上,我们可以这样做:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Session["HotelPK"] == null)
{
// no value - lets jump to View Hotels page
Response.Redirect("GridRowSel.aspx");
}
else
{
ViewState["HotelPK"] = Session["HotelPK"];
ShowHotelInfo();
}
}
}
void ShowHotelInfo()
{
// code here to load Hotel information from ViewState[HotelPK]
using (SqlCommand cmdSQL =
new SqlCommand("SELECT * FROM tblHotels WHERE ID = @ID" ,
new SqlConnection(Properties.Settings.Default.TEST3)))
{
cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = ViewState["HotelPK"];
cmdSQL.Connection.Open();
Repeater1.DataSource = cmdSQL.ExecuteReader();
Repeater1.DataBind();
}
}
所以在上面,我们使用中继器控件来呈现一个酒店记录。
所以使用 session() 传递值的“规则”是可以的,但请注意我做的第一件事是将会话转移到 ViewState。我这样做是因为用户可以右键单击,甚至启动另一个浏览器。因此,如果有两家酒店营业,那么两个页面都可以正常运行,我不在乎会话值是否发生了变化。
另一种坚持的方法?
我们经常在网页上使用控件——甚至是隐藏的控件。这通常很方便,因为客户端 JS 代码也可以在页面上使用此类值。
所以,这应该会给你一些想法。