.net中保存用户信息的九种方法

在ASP.NET中,有几种保持用户请求间数据的途径--实际上太多了,使没有经验的开发者对在哪个特定的环境下使用哪个对象很困惑。为了回答这个问题,需要考虑下面三个条件:

   .谁需要数据?

   .数据需要保持多长时间?

   .数据集有多大?

  通过回答这些问题,你能决定哪个对象为保持ASP.NET应用程序请求间数据提供了最佳的解决方案。图1列出了不同的状态管理对象并描述了什么时候使用它们。ASP.NET中添加了四个新的对象:Cache、Context、ViewState和Web.Config文件。ASP.NET也支持传统的ASP对象,包括Application、 Cookie、有隐藏字段的 Form Post 、 QueryString和Sessions。注意这五个数据容器的正确使用方法发生了改变,因此有经验的程序员在考虑这些熟悉的对象时也许需要学习一些知识。


保持方法 谁需要数据 保持多长时间 数据量大小
Application 所有用户 整个应用程序生命期 任意大小
Cookie 一个用户 可以很短,如果用户不删除也可以很长 小的、简单数据
Form Post 一个用户 到下一次请求(可以跨越多个请求重复使用) 任意大小
QueryString 一个或一组用户   到下一次请求(可以跨越多个请求重复使用) 小的、简单数据
Sessions 一个用户 用户活动时一直保持+一段时间(一般20分钟) 可以是任何大小,但是因为用户有单独的Sessions 存储,所有它应该最小。
Cache   所有用户或某些用户 根据需要 可大可小、可简单可复杂
Context 一个用户   一个请求 可以保持大对象,但是一般不这样使用
ViewState   一个用户 一个Web窗体 最小
Config file 所有用户   知道配置文件被更新   可以保持大量数据,通常组织小的字符串和XML结构


表1. ASP.NET中的数据容器对象

  Application

  让我们通过回答上面的状态问题判定条件来说明该对象。谁需要数据?所有的用户需要访问它。需要保持数据多长时间?永久保持,或在应用程序生存期中保持。数据多大?可以是任何大小--在任何给定的时刻只有数据的一个副本存在。

  在传统ASP中,Application对象提供了一个保存频繁使用但很少改变的数据片的位置,例如菜单内容和参考数据。尽管在ASP.NET 中Application依然作为数据容器存在,但是有其它一些更适合以前保存在传统ASP应用程序的Application集合中的数据的对象。

  在传统的ASP中,如果被保存的数据在应用程序的生存期中根本不会改变(或很少改变,例如只读数据和大多数情况下是读操作的数据),Application对象是理想的选择。连接字符串就是保存在Application变量中的一个最普通的数据片,但是在ASP.NET中类似的配置数据最好保存在Web.config文件中。如果使用Application对象一个需要考虑的问题是任何写操作要么在Application_OnStart事件(global.asax)中,要么在Application.Lock部分中完成。尽管使用Application.Lock来确保写操作正确地执行是必要的,但是它串行化了对Application对象的请求,而这对于应用程序来说是个严重的性能瓶颈。图2演示了怎样使用Application对象,它包括一个Web窗体和它的代码文件。

  Application.aspx


<form id="Application" method="post" runat="server">
<asp:validationsummary id="valSummary" Runat="server">
</asp:validationsummary>
<table>
<tr>
<td colSpan="3">Set Application Variable:</td>
</tr>
<tr>
<td>Name</td>
<td><asp:textbox id="txtName" Runat="server"></asp:textbox>
</td>
<td><asp:requiredfieldvalidator id="nameRequired"
runat="server" Display="Dynamic" ErrorMessage="Name is
required." ControlToValidate="txtName">*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td>Value</td>
<td><asp:textbox id="txtValue" Runat="server">
</asp:textbox></td>
<td><asp:requiredfieldvalidator id="valueRequired"
Runat="server" Display="Dynamic" ErrorMessage="Value is
required." ControlToValidate="txtValue">*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td colSpan="3"><asp:button id="btnSubmit" Runat="server"
Text="Update Value"></asp:button></td>
</tr>
</table>
<asp:Label ID="lblResult" Runat="server" />
</form>
Application.aspx.cs
private void btnSubmit_Click(object sender, System.EventArgs e)
{
if(IsValid)
{
Application.Lock();
Application[txtName.Text] = txtValue.Text;
Application.UnLock();
lblResult.Text = "The value of <b>" + txtName.Text +
"</b> in the Application object is <b>" +
Application[txtName.Text].ToString() + "</b>";
}
}  

代码段1.在ASP.NET中访问Application对象

  它的输出如下图所示:

 

图1. Application对象的内容

  注意图3中Application对象的内容是追踪输出的显示。追踪是个伟大的调试工具,但是在某个点,被打开的有追踪的页面可能出现在产品环境中。如果出现这种情况,你肯定不希望显示敏感的信息。这就是为什么Application对象从来不是推荐的存放敏感信息(例如连接字符串)的位置的主要原因之一。


  Cookies

  当特定的用户需要特定的数据片,并且需要把数据在某个可变的时段中保持的时候,cookie就非常方便。它的生命周期可能与浏览器窗体的一样短,也可以长达数月、数年。cookie可以小到只有几个字节的数据,因为它们在每个浏览器请求中传递,它们的内容需要尽可能的小。

  Cookie提供了一条灵活的、强大的维护用户请求间数据的途径,这就是为什么Internet上大多数动态站点使用它们的原因。因为cookie可以存储的数据量很受限制,最好只在cookie中保存键字段,其它的数据保存在数据库或其它的服务器端数据容器中。但是由于不是所有的浏览器都支持cookie,并且它可以被用户禁止或删除,因此它们也不能用于保存关键数据。你应该很好地处理用户的cookie被删除的情况。最后,cookie作为简单的明文文本保存在用户的计算机中,因此在它里面不能保存敏感的、未加密的数据。


图2.单值和多值cookie

  有种特殊的cookie可以保存单个值或名称/值对的集合。图4显示了单个和多个值cookie的示例,通过ASP.NET的内建追踪特性输出。这些值可以在ASP.NET页面中使用Request.Cookies和Response.Cookies集合来维护,这在代码段2中演示。

  Cookies.aspx.cs

//使用HttpCookie类是指cookie的值和/或子值
HttpCookie cookie;
if(Request.Cookies[txtName.Text] == null)
cookie = new HttpCookie(txtName.Text, txtValue.Text);
else
cookie = Request.Cookies[txtName.Text];
if(txtSubValueName.Text.Length > 0)
cookie.Values.Add(txtSubValueName.Text, txtSubValueValue.Text);
cookie.Expires = System.DateTime.Now.AddDays(1); // tomorrow
Response.AppendCookie(cookie);
//检索cookie的值
if(!Request.Cookies[txtName.Text].HasKeys)
lblResult.Text = "The value of the <b>" + txtName.Text + "</b>
cookie is <b>" + Request.Cookies[txtName.Text].Value.ToString() +
"</b>";
else
{
lblResult.Text = "The value of the <b>" + txtName.Text + "</b>
cookie is <b>" + Request.Cookies[txtName.Text].Value.ToString() +
"</b>, with subvalues:<br>";
foreach(string key in Request.Cookies[txtName.Text].Values.Keys)
{
lblResult.Text += "[" + key + " = " +
Request.Cookies[txtName.Text].Values[key].ToString() + "]<br>";
}
}
删除Cookie
// 把的值设置为空并把终止时间设置为过去某个时刻
Response.Cookies[txtName.Text].Value = null;
Response.Cookies[txtName.Text].Expires =
System.DateTime.Now.AddMonths(-1); //上个月

代码段2.Accessing 在ASP.NET中访问Cookies

  Form Post / 隐藏的窗体字段

  特定的用户需要窗体的数据,并且它需要在单个请求到应用程序终止的任何阶段都保持。这些数据事实上可以是任意大小的,它随着每个form post在网络上向前和向后发送。

  在传统的ASP中,这是在应用程序中暴露状态的通常的途径,特别是在多页面窗体应用程序中。但是在ASP.NET中这种技术不太适合了,因为只要你使用postback模型(也就是页面发回给自己),Web控件和ViewState自动处理了这些操作。ViewState是ASP.NET对这种技术的实现,我将在本文的后部分讨论它。访问通过POST发送的窗体值是使用HttpRequest对象的窗体集合完成的。在图6中,一个ASP.NET页面设置了某个用户的ID,在这以后它保持在一个隐藏的窗体字段中。后面的向任何页面的请求保留这个值,直到页面使用Submit按钮链接到其它的用户。

  Form1.aspx


<h1>Form 1</h1>
<form id="Application" method="post" runat="server">
<p>Your username:
<asp:Label ID="lblUsername" Runat="server" />
</p>
<asp:Panel Runat="server" ID="pnlSetValue">
<asp:validationsummary id="valSummary" Runat="server">
</asp:validationsummary>
<TABLE>
<TR>
<TD colSpan="3">Set Hidden Form Username Variable:</TD></TR>
<TR>
<TD>Username</TD>
<TD>
<asp:textbox id="txtName" Runat="server"></asp:textbox></TD>
<TD>
<asp:requiredfieldvalidator id="nameRequired" runat="server"
ControlToValidate="txtName" ErrorMessage="Name is required."
Display="Dynamic">*</asp:requiredfieldvalidator></TD></TR>
<TR>
<TD colSpan="3">
<asp:button id="btnSubmit" Runat="server" Text="Set Value">
</asp:button></TD></TR></TABLE>
</asp:Panel>
<asp:Label ID="lblResult" Runat="server" />
</form>
<form action="form2.aspx" method="post" name="form2" id="form2">
<input type="hidden" name="username" value="<%# username %>" >
<input type="submit" value="Go to Form2.aspx"
</form>
Form1.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
{
if(!IsPostBack) // 新的请求或者来自form2.aspx的请求
{
// 检查窗体集合
if(Request.Form["username"] == null)
pnlSetValue.Visible = true;
else
{
//需要设置用户名值
pnlSetValue.Visible = false;
username = Request.Form["username"].ToString();
lblUsername.Text = username;
//数据绑定到隐藏的窗体字段值
this.DataBind();
}
}
}

private void btnSubmit_Click(object sender, System.EventArgs e)
{
if(IsValid)
{
//隐藏窗体来设置值
pnlSetValue.Visible = false;
username = txtName.Text;
lblResult.Text = "Username set to " + txtName.Text + ".";
lblUsername.Text = username;
this.DataBind();
}
}
Form2.aspx
<h1>Form 2</h1>
<form id="Application" method="post" runat="server">
<p>Your username: <asp:Label ID="lblUsername" Runat="server" /></p>
</form>
<form action="form1.aspx" method="post" id="form2" name="form2">
<input type="hidden" name="username" value="<%# username %>" >
<input type="submit" value="Go to Form1.aspx"
</form>
Form2.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
{
if(Request.Form["username"] != null)
{
username = Request.Form["username"].ToString();
lblUsername.Text = username;
this.DataBind();
}
}

代码段3.在ASP.NET中使用隐藏窗体字段

  在ASP.NET中一个页面上只能存在一个服务器端窗体,并且该窗体必须提交返回到自身(仍然可以使用客户端窗体,没有限制)。隐藏窗体字段再也没有用于在.NET框架组件上建立的应用程序间传递数据的主要原因之一是.NET框架组件控件都可以使用ViewState自动维护自己的状态。ViewState简单地把使用隐藏窗体字段设置和检索值所包含的工作封装进一个使用简单的集合对象中。

  QueryString

  QueryString对象中保存的数据由单独的用户使用。它的生命周期可能只有一个请求那么短,也可能有用户使用应用程序的时间那么长(如果构造正确的话)。这类数据一般小于1KB。QueryString中的数据在URL中传递,对于用户来说是可见的,因此你能猜到,使用这种技术时,敏感的数据或可用于控制应用程序的数据需要加密。

  也就是说,QueryString是在ASP.NET Web窗体间发送信息的一条很好的途径。例如,如果有一个含有产品列表的数据表格(DataGrid),并且在表格上有一个链接导向产品的细节页面,使用QueryString就是理想的,可以把产品的ID包含在链接到产品细节页面的QueryString中(例如productdetails.aspx?id=4)。使用QueryStrings的另一个好处是页面的状态包含在URL中。这意味着用户可以把某个通过QueryStrings建立的窗体放入他的收藏夹中。当它们作为收藏返回到页面时,将与作收藏的时候一样。很明显这只在页面不依赖QueryString外的所有状态和不作任何改变的时候有作用。

  敏感数据,以及任何不希望用户操作的变量应该避免出现在此处(除非加密使用户不能阅读)。并且URL中不合法的字符必须使用Server.UrlEncode编码,如图7所示。当处理单个ASP.NET页面时,对维护状态来说ViewState是比QueryString好的选择。对于长期的数据存储,Cookie、Sessions或Cache都比QueryStrings更加适于作为数据容器。

  Querystring.aspx


<form id="Querystring" method="post" runat="server">
<asp:validationsummary id="valSummary" Runat="server">
</asp:validationsummary>
<table>
<tr>
<td colSpan="3">Set Querystring Variable:</td>
</tr>
<tr>
<td>Name</td>
<td><asp:textbox id="txtName" Runat="server"></asp:textbox>
</td>
<td><asp:requiredfieldvalidator id="nameRequired"
runat="server" Display="Dynamic" ErrorMessage="Name is
required." ControlToValidate="txtName">*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td>Value</td>
<td><asp:textbox id="txtValue" Runat="server">
</asp:textbox></td>
<td><asp:requiredfieldvalidator id="valueRequired"
Runat="server" Display="Dynamic" ErrorMessage="Value is
required." ControlToValidate="txtValue">*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td colSpan="3"><asp:button id="btnSubmit" Runat="server"
Text="Update Value"></asp:button></td>
</tr>
</table>
<asp:Label ID="lblResult" Runat="server" />
<a href="querystring.aspx?x=1">Set querystring x equal to 1</a>
</form>
Querystring.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
{
// 检索cookie的值
if(Request.QueryString.HasKeys())
{
lblResult.Text = "The values of the <b>" + txtName.Text +
"</b> querystring parameter are:<br>";
foreach(string key in Request.QueryString.Keys)
{
lblResult.Text += "[" + key + " = " +
Request.QueryString[key].ToString() + "]<br>";
}
}
}

private void btnSubmit_Click(object sender, System.EventArgs e)
{
if(IsValid)
{
string url = "querystring.aspx?";
foreach(string key in Request.QueryString.Keys)
{
url += key + "=" + Request.QueryString[key].ToString() + "&";
}
Response.Redirect(url + txtName.Text + "=" +
Server.UrlEncode(txtValue.Text));
}
}

代码段4.在ASP.NET中使用QueryStrings传递数据


  Sessions

  Sessions数据对于特定的用户是特定的。它的生存期是用户持续请求的时间加上后来一段时间(一般是20分钟)。Sessions可以保持或大或小的数据量,但是如果应用程序用于成百上千的用户,那么总共的存储应该保持最小。

  不幸的是在传统的ASP中Sessions对象的名声很不好,因为它把应用程序约束到特定的计算机上,阻碍了用户分组和Web范围的可伸缩性。在ASP.NET中几乎没有这些问题,因为改变Sessions保存的位置很简单。在默认情况下(性能最好的情况),Sessions数据仍然保存在本地Web服务器的内存中,但是ASP.NET支持使用外部状态服务器或数据库管理Sessions数据。

  使用Sessions对象很简单,并且它的语法与传统ASP相同。但是Sessions对象是保存用户数据的方法中效率很低的一种,因为即使用户停止使用应用程序后它仍然保持在内存中一段时间。这对于非常繁忙的站点的可伸缩性有严重的影响。其它的选择允许对释放内存的更多的控制,例如Cache对象也许更适合大量的大数据值。并且在默认情况下ASP.NET Sessionss依赖于cookie,因此如果用户禁止或不支持cookie,Sessionss就不能工作,但是可以配置Sessionss支持cookie无关。对于小的数据量,Sessionss对象是保存只需要在用户当前对话中保持的特定数据的极好位置。下面的例子演示了怎样设置和从Sessionss对象中检索值:


private void btnSubmit_Click(object sender, System.EventArgs e)
{
 if(IsValid)
 {
  // 设置Sessions值
  Sessions[txtName.Text] = txtValue.Text;

  //读取和显示刚才的设置
  lblResult.Text = "The value of <b>" + txtName.Text + "</b> in the Sessions object is <b>" + Sessions[txtName.Text].ToString() + "</b>";
 }
}

  该Web窗体与Application对象中使用的几乎相同,当允许页面追踪时Sessions集合的内容也是可见的。
你需要记住的是即使没有使用,Sessionss也会有应用程序开销。把Sessionss状态设置为只读的也可以优化只需要读而不需要写数据的页面。可以使用下面两种途径之一来配置Sessionss:


<%@ Page EnableSessionsstate="false" %>
<%@ Page EnableSessionsstate="readonly" %>

  ASP.NET Sessionss可以在Web.config或Machine.config中的Sessionsstate元素中配置。下面是在 Web.config中的设置的例子:


<Sessionsstate timeout="10" cookieless="false" mode="Inproc" />


  ASP.NET中的新状态容器

  前面我们提到,ASP.NET为保存用户请求间的数据添加了几种新的途径。这些途径给了你如何保持状态信息更好的控制。这些技术的范围可以窄到只有一个请求那么小(Context对象),也可以宽到整个Web服务器和服务器上的所有应用程序(Machine.config文件)。在多数情况下你有多种保存特定数据片的选择--使用每个方法描述的问题和答案来决定某个对象是否适合你的需要。

  Cache

  Cache对象用于单个用户、一组用户或所有的用户。这种数据为多个请求保持。它可以保持很长时间,但是不能超过应用程序重新启动的时间,并且数据的终止基于时间或者其它的依赖关系。它可以高效率地保持大量或少量地数据。

  Cache 是ASP.NET中最"酷"的对象之一。它提供了难以置信的灵活性、通用性和性能,因此在ASP.NET应用程序中它通常是比Application或Sessions更好的保持数据的对象。本文没有详细介绍Cache对象的使用方法,但是仍然可以说它是一个万能对象。与其它的集合对象相似,它是一个简单的名称-值集合,但是通过使用指定特定用户的键值可以缓存特定用户的值。同样你可以缓存不同的相关数据的多个数据集,例如几个有键(如fordcars 、 chevycars、gmcars)的汽车集合。Cache中的数据可以给定一个绝对的、可变的或基于文件的终止时间。它们也实现了一个回调功能,在被缓存的值从缓存中提取时被调用,这个功能很有用,因为接着你能检查它是否为最新的数据变量,如果不是(或数据源不可用),就重新缓存被终止的值。

  添加和访问缓存中值的语法与先前谈到的相似。但是Cache给访问集合内容的标准索引器方法作了补充,它支持多种方法,允许对被缓存数据的更多的控制。最频繁使用的方法是Insert,它支持几种重载,允许你指定依赖、超时值、优先级和回调。下面是一些简单的例子:


// 给缓存添加项
Cache["myKey"] = myValue;

// 从缓存中读取项
Response.Write(Cache["myKey"]);

// 把CacheDuration增加10秒并把项添加到缓存中
Cache.Insert("myKey",myValue, null, System.DateTime.Now.AddSeconds(10),
System.Web.Caching.Cache.NoSlidingExpiration);

  Cache对象的最强大的特性之一是当缓存中的某个项终止时执行回调的能力。它使用了委托或函数指针,这在本文中没有讨论。幸运的是一旦你有了某些这些技术怎样工作的示例,就能通过简单的剪切和粘贴在应用程序中使用它们,不需要知道委托是怎样工作的复杂过程。有很多使用这种功能的原因,最通常的是在数据终止时用当前数据重新填充缓存,或者如果重新填充缓存的数据源不可用时恢复旧的缓存数据。

  在我的例子中,简单地缓存了当前时间,当缓存超期的时候,我将给缓存中的字符串末尾添加一个星号(*)。在超过时间后,你能通过计算星号的数量来确定缓存超期了多少次。图9演示了回调的重要概念,并且提供了给使用缓存建立更多功能回调程序的好模板。


private void Page_Load(object sender, System.EventArgs e)
{
 string cacheKey = "myKey";
 string data = "";
 // 检查数据是否已经被缓存了
 if(Cache[cacheKey]==null)
 {
  // 因为数据在缓存中,所有读取数据
  data = System.DateTime.Now.ToString();

  //建立回调委托的一个实例
  CacheItemRemovedCallback callBack =new CacheItemRemovedCallback(onRemove);

  Label1.Text = "Generated: " + data;

  Cache.Insert(cacheKey,data,null,
      System.DateTime.Now.AddSeconds(5),
      System.Web.Caching.Cache.NoSlidingExpiration,
      System.Web.Caching.CacheItemPriority.Default,
      callBack);
 }
 else
 {
  Label1.Text = "Cached: " + Cache[cacheKey].ToString();
 }
}

private void onRemove(string key, object val,CacheItemRemovedReason reason)
{
 //建立回调委托的一个实例
 CacheItemRemovedCallback callBack =new CacheItemRemovedCallback(onRemove);
    Cache.Insert(key,val.ToString() +
    "*",null,System.DateTime.Now.AddSeconds(5),Cache.NoSlidingExpiration,
    System.Web.Caching.CacheItemPriority.Default, callBack);
}

代码段5.缓存回调示例

  注意代码段中一个重要的特性是在Page_Load中使用模式(pattern)来确定是否使用缓存中的数据。当你处理缓存中的项时也可能使用这种模式。使用if语句来检查缓存的当前内容是否为空(因为要多次引用,为缓存键使用了一个变量)。如果是空的,从数据源生成数据并放入缓存中。如果不是空的,从缓存中返回数据。如果数据访问逻辑很复杂,你需要把整个if语句放入一个独立的函数,该函数的任务是检索数据。
Cache对象的功能比先前我们讨论的大多数对象多得多。这也是ASP.NET更强大的功能之一,并且我明确地推荐阅读关于它的更多内容。

  Context

  Context对象保持单个用户、单个请求的数据,并且数据只在该请求期间保持。Context容器可以保持大量的数据,但是典型的情况下是保存小的数据片,因为它经常通过global.asax中的某个处理方法为每个请求实现。

  Context容器(从Page对象访问或使用System.Web.HttpContext.Current)被提供用于保持需要在不同的HttpModules和HttpHandlers之间传递的值。它也可以用于保持某个完整请求的相应信息。例如,IbuySpy入口在global.asax中的Application_BeginRequest事件过程中给容器填满了许多配置信息。注意这只在当前请求中可用,如果你希望在下一个请求中也能使用,请考虑使用ViewState。

  从Context集合中设置和获取数据使用的语法与前面讨论的其它集合对象(如Application、Sessions和 Cache)的相似。下面是两个简单的例子:


// 给Context添加项
Context.Items["myKey"] = myValue;

// 从Context中读取项
Response.Write(Context["myKey"]);

 

  ViewState

  ViewState为单个用户保持状态信息,保持期为ASPX页面工作时间。ViewState容器可以保持大量的数据,但是必须小心管理ViewState的大小,因为它增加了每个请求和回应的下载(download)大小。

  ViewState是ASP.NET中的一个新容器,也许你已经使用它了,但是你可能还是不了解它。这是因为所有的内建Web控件都使用ViewState在页面回发(postback)间保持自己的值。但是你必须小心,因为它影响应用程序的性能。影响的大小依赖于回发之间使用ViewState的多少--对大多数Web窗体来说数量非常小。

  确定某个页面上每个控件使用的ViewState的数量最简单的方法是打开页面追踪并检查每个控件负载了多少个ViewState。如果某个特定控件不需要在回发之间保持数据,请通过把EnableViewState设置为false关闭该对象的ViewState。你也可以通过在浏览器中查看的HTML源并检查隐藏窗体字段__VIEWSTATE来确定某个给定的ASP.NET页面ViewState的总共大小。注意这些内容都是使用Base64编码的,用于放置偶然的查看和维护。ViewState也可以通过给@Page指令添加EnableViewState="false"在整个页面中禁止。

  典型的Web窗体不需要直接维护ViewState。但是如果你建立自定义Web控件,就需要了解它是怎样工作的,并为你的控件实现它,这样该控件的工作方式才能与随ASP.NET发布的Web控件同样地工作。向ViewState读取或写入值都可以通过上面讨论地其它集合对象的语法完成:


// 给ViewState添加项
ViewState["myKey"] = myValue;

//从Context读取项
Response.Write(ViewState["myKey"]);

  当建立自定义Web控件时,你也许希望它们有ViewState的好处。这在控件的属性层可以简单实现。代码段6演示了怎样保存一个简单的自定义控件的PersonName属性到ViewState中,并在该控件的Render方法中使用它。


namespace MSDN.StateManagement
{
 public class HelloPerson : System.Web.UI.Control
 {
  public string PersonName
  {
   get
   {
    string s = (string)ViewState["PersonName"];
    return ((s == null) ? "" : s);
   }
   set
   {
    ViewState["PersonName"] = value;
   }
  }
  protected override void Render(System.Web.UI.HtmlTextWriter writer)
  {
   writer.Write("Hello " + PersonName);
  }
 }
}

代码段6.在ViewState中保存数据

  Web.config和Machine.config文件

  这些文件中的数据对于某个应用程序的所有用户来说都可以使用。Web.config文件中存储的数据可用于应用程序的整个生命周期。这些数据一般很小,该对象一般用于保持文件位置和数据库连接的字符串。大的数据片最好保存在其它位置。

  作为其它多样集合对象的补充,ASP.NET引入了一组XML配置文件用于管理应用程序甚至于整个服务器的很多设置。每个ASP.NET应用程序使用Web.config文件来设置它的许多属性,每个服务器在系统文件夹下有一个作为应用程序基础的Machine.config文件。这些设置都作为默认值使用,除非重载。作为保存配置数据的补充,这些文件可以保存应用程序(或多个应用程序)需要的数据。

  无论什么时候应用程序启动都会读取配置信息,接着这些信息被缓冲。由于被缓冲了,应用程序可以快速读取它们,因此不需要考虑应用程序的瓶颈,因为它经常执行某个文本文件的一些整型信息。此外,某个应用程序的Web.config的改变将导致应用程序重新启动。这确保了对配置文件信息的修改立即反映到应用程序中。

  数据库连接信息,默认图像路径和XML数据文件路径是通常保存在Web.config文件中的数据片。在Web.config文件中保存数据的语法如下,在理想的情况下你也许希望使用集成的SQL身分验证:


<configuration>
<!-应用程序特殊设置 -->
<appSettings>
<add key="connectionString" value="server=myDBServer;
uid=myUID;pwd=myPassword;database=myDB" />
</appSettings>
<system.web>
<!-所有的wsb设置 -->
</system.web>
</configuration>  

  为了访问ASP.NET页面中的值,可以使用ConfigurationSettings集合,它在System.Configuration名字空间中。下面的简单例子演示了怎样提取前面的连接字符串到一个本地变量中:

using System.Configuration;
ooo
String strConnString =
ConfigurationSettings.AppSettings["connectionString"];

  给System.Configuration名字空间添加一个引用减少了引用这些值的代码数量。因为对Web.config或 Machine.config的修改将导致应用程序立即重新启动,典型情况下这些值只由服务器系统管理员手动修改。因此你可以认为这些文件是保存只读数据而不是应用程序中修改的数据的好位置。

  结论

  有效的状态管理意味着识别的用户经验、数据错误与快速的页面或事务处理之间的巨大差别。尽管状态管理在ASP 3.0中不太适用,但是ASP.NET把它带到了本文讨论的状态对象的控制之下。小心地使用它们将使你给用户展示最佳的Web经验。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
不定项选择题(共14题,单选或多选): 一、一个HTML文档必须包含三个元素,它们是head、html和( )。 A.scriptB.bodyC.titleD.link 二、下面哪段javascript能弹出一个提示框?( ) A.document.alert(test) B.window.alert(test) C.document.alert('test ') D.window.alert('test ') 三、当鼠标放在一个链接上的css样式应该( )伪类来定义。 A.a:visitedB.a:linkC.a:hoverD.a:active 四、关于ASP.NET的代码隐藏文件的描述正确的是( )。 A.Web窗体页的程序的逻辑由代码组成,这些代码的创建用于与窗体交互。该文件称作为“代码隐藏”文件,如果用C#创建,该文件将具有“.ascx.cs”扩展名 B.web窗体也是类 C.项目所有的Web窗体页的代码隐藏文件都被编译成项目动态链接库(.dll)文件 D.以上都不正确 五、下列ASP.NET语句( )正确地创建了一个与SQL Server数据库的连接。 A.SqlConnection con1 = new Connection(“Data Source = localhost; Trusted_Connection =Yes; Initial Catalog = myDB”); B.SqlConnection con1 = new SqlConnection(“Data Source = localhost; Trusted_Connection =Yes; Initial Catalog = myDB”); C.SqlConnection con1 = new OleDbConnection(“Data Source = localhost; Trusted_Connection =Yes; Initial Catalog = myDB”); D.SqlConnection con1 = new SqlConnection(Data Source = localhost; Trusted_Connection =Yes; Initial Catalog = myDB); 六、执行一次无返回值的数据删除,必须用到下面哪些对象? ( ) A.SqlConnectionB.SqlDataAdapterC.SqlCommandD.SqlDataReader 七、在ADO.NET,对于Command对象的ExecuteNonQuery()方法和ExecuteReader()方法,下面叙述错误的是( ) A.insert、update、delete等操作的Sql语句主要用ExecuteNonQuery()方法来执行; B.ExecuteNonQuery()方法返回执行Sql语句所影响的行数。 C.Select操作的Sql语句只能由ExecuteReader()方法来执行; D.ExecuteReader()方法返回一个DataReder对象; 八、ASP.NET有多种维护状态的技术,以下哪种是保存在客户端的?( ) A.VIEWSTATEB.SESSIONC.APPLICATIOND.数据CACHE 九、Cookies的默认生命周期有多长? ( ) A.20分钟B.30分钟C. 一天D.随浏览器的关闭而失效 十、int[][] myArray=new int[3][]{ new int[3]{ 5, 6, 2 }, new int[5]{ 6, 9, 7, 8, 3 }, new int[2]{ 3, 2 }}; myArray[2][2]的值是( ) A.9B.2C.6D.越界 十一、要为做了输出缓存的页面实现即时判断用户IP来路,可在以下哪种事件实现? ( ) A.Page.InitB.HttpApplication.BeginRequest C.Page.LoadD.以上都不是 十二、下面哪个SQL语句完全正确( ) A.Select count(*) from (select top 10 * from table order by bb) tb group by cc B.update set bb = bb + 1 from table C.Select count(*) from (select distinct * from table) tb group by cc D.delete * from table 十三、为了实现a.aspx的URL重写,下面哪个正则表达式替换可以实现?( ) A. Regex.Replace(sUrl, @“/(\d+).aspx”, “a.aspx?ID=$0”, RegexOptions.IgnoreCase) B. Regex.Replace(sUrl, @“/(\d+).aspx”, “/a.aspx?ID=$0”, RegexOptions.IgnoreCase) C. Regex.Replace(sUrl, @“/(\d+).aspx”, “a.aspx?ID=$1”, RegexOptions.IgnoreCase) D. Regex.Replace(sUrl, @“/(\d+).aspx”, “/a.aspx?ID=$1”, RegexOptions.IgnoreCase) 十四、下面javascript代码的输出结果是( ) var aa = new Array(1, 2, 4, 5, 3, 6); var c = 0; for (var i = 0; i < aa.length; ++i){ c += aa.pop(); } document.write(c); 提示:Array.pop()函数将数组内最后一个元素移除并返回该元素 A.7 B.14 C.21 D.以上皆不正确 填空题(共4题): 一、C#判断整型变量k是否偶数的语句: 二、有这样的枚举定义:public enum TrainType{ 空调, 快速, 新型, 卧铺 },为实现它的按位组合,你会分别赋予它们什么值?请用逗号按顺序分隔开 三、C#为了防止非本程序集的代码访问,可以用什么关键字修饰类或者类成员? 四、为了将table表内bb(datetime类型)字段的数据按年月降序输出,对应的SQL语句为 选择题答案: 1.B,2.D,3.C,4.BC,5.B,6.AC,7.C,8.A,9.D,10.D,11.B,12.AC,13.D,14.B 填空题答案: 1.(k & 1) == 0 或 k % 2 == 0 2.1,2,4,8(答案不定,看情况) 3.internal 4.select * from table order by year(bb) desc, month(bb) desc 1.new有几种用法 第一种:new Class(); 第二种:覆盖方法 public new XXXX(){} 第三种:new 约束指定泛型类声明的任何类型参数都必须有公共的无参数构造函数。 2.如何把一个array复制到arrayList里 foreach( object o in array )arrayList.Add(o); 3.datagrid.datasouse可以连接什么数据源 [dataset,datatable,dataview] dataset,datatable,dataview , IList 4.概述反射和序列化 反射:程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型。然后,可以调用类型的方法或访问其字段和属性 序列化:序列化是将对象转换为容易传输的格式的过程。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。在另一端,反序列化将从该流重新构造对象。 5.概述o/r mapping 的原理 利用反射,配置 将类于数据库表映射 6.类成员有( )种可访问形式 可访问形式?不懂。 可访问性:public ,protected ,private,internal 7.用sealed修饰的类有什么特点 sealed 修饰符用于防止从所修饰的类派生出其它类。如果一个密封类被指定为其他类的基类,则会发生编译时错误。 密封类不能同时为抽象类。 sealed 修饰符主要用于防止非有意的派生,但是它还能促使某些运行时优化。具体说来,由于密封类永远不会有任何派生类,所以对密封类的实例的虚拟函数成员的调用可以转换为非虚拟调用来处理。 8.列举ADO.NET的五个主要对象,并简单描述 connection,command,dataReader,trans,dataset ... 9.执行下面代码后: String strTemp ="abcdefg 某某某"; Int i System.Text.Encoding.Default.GetBytes(strTemp).Length; Int j = strTemp.Length; 问:i=(14 ) ;j=(11 ) i=(14 ) ;j=(11 ) 文两个字节 10.C#,string str = null 与 string str ="",请尽量用文字说明区别。(要点:说明详细的内存空间分配) string str ="" 分配空间 11.详述.NET里class和struct的异同! class:放在 ? struct放在? struct值传递 类与结构有很多相似之处:结构可以实现接口,并且可以具有与类相同的成员类型。然而,结构在几个重要方面不同于类:结构为值类型而不是引用类型,并且结构不支持继承。结构的值存储在“在堆栈上”或“内联”。细心的程序员有时可以通过聪明地使用结构来增强性能。 12.概述.NET里对 remoting 和 webservice 两项技术的理解和实际的应用。 远程逻辑调用,remoing接口只能用在.net 13.什么是code-behind技术 aspx and cs 14.概述三层结构体系 web/business/dataaccess 15.asp.net如何实现MVC模式,举例说明! web/business/dataaccess ---------------------------------------------------------------------------------------------------------- 1.面向对象的思想主要包括什么? 答:这个题范围太广,不知道说什么. 2.什么是ASP.net用户控件 答:用户控件就是.ascx扩展名的东西喽,可以拖到不同的页面调用,以节省代码.比如登陆可能在多个页面上有,就可以做成用户控件,但是有一个问题就是用户控件拖到不同级别的目录下后里面的图片等的相对路径会变得不准确,需要自已写方法调整. 3.什么叫应用程序域?什么是受管制的代码?什么是强类型系统?什么是装箱和拆箱?什么是重载?CTS、CLS和CLR分别作何解释? 答:装箱就是把值类型转成引用类型,从MS IL角度看好像是boxing,没记错的话是把值从堆栈转到堆.拆箱相反,重载就是指一个方法名同,参数个数不同,返回值可以相同的方法.CLR是通用语言运行时,其它的不清楚. 4.列举一下你所了解的XML技术及其应用 答:XML可是好东西,保存配置,站与站之间的交流,WEB SERVICE都要用它. 5.值类型和引用类型的区别?写出C#的样例代码。 答:结构是值类型,类是引用类型,所以传结构就是值类型的应用啦,传对象或类就是引用类型的,这个不用多写了吧. 6.ADO.net常用的对象有哪些?分别描述一下。 答:connection command sqladapter dataset datatable dataview等等.写不完了. 7.如何理解委托? 答:据说相当于函数指针,定义了委托就可以在不调用原方法名称的情况下调用那个方法. msdn2005是这样解释的: 委托具有以下特点: 委托类似于 C++ 函数指针,但它是类型安全的。 委托允许将方法作为参数进行传递。 委托可用于定义回调方法。 委托可以链接在一起;例如,可以对一个事件调用多个方法方法不需要与委托签名精确匹配。有关更多信息,请参见协变和逆变。 C# 2.0 版引入了匿名方法的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。 8.C#的接口和类有什么异同。 答:这个异同可多了,要说清楚还真不容易. 9.。net读写数据库需要用到哪些类?他们的作用 答:这个类自已可以写的啊,你是指基类吗?那configuration,sqlconnection,sqlcommand等都要用到. 10.UDP连接和TCP连接的异同。 答:前者只管传,不管数据到不到,无须建立连接.后者保证传输的数据准确,须要连结. 11.ASP.net的身份验证方式有哪些?分别是什么原理? 答:form认证,windows集成认证等,原理不清楚. 12.进程和线程分别怎么理解? 答:进程是老子,线程是儿子,没有老子就没有儿子,一个老子可以有多个儿子.一个儿子可以成为别人的儿子,一个老子也可以为别的老子生儿子. 13.什么是code-Behind技术。 答:代码分离,这是个明智的东西,像ASP这样混成一堆很不爽.或者可以理解成HTML代码写在前台,C#代码写在后台.当然前台也有脚本,类的调用等,其实写在一起也是可以的. 14.活动目录的作用。 答:这个不明白.请明白的补充一下. 15..net读写XML的类都归属于哪些命名空间? 答:System.Xml 我自已写的就不一定了,嘿嘿. 16.解释一下UDDI、WSDL的意义及其作用。 答:什么东西? 17.什么是SOAP,有哪些应用。 答:SOAP(Simple Object Access Protocol )简单对象访问协议是在分散或分布式的环境交换信息并执行远程过程调用的协议,是一个基于XML的协议。使用SOAP,不用考虑任何特定的传输协议(最常用的还是HTTP协议),可以允许任何类型的对象或代码,在任何平台上,以任何一直语言相互通信。这种相互通信采用的是XML格式的消息,具体请看:http://playist.blogchina.com/2521621.html 18.如何部署一个ASP.net页面。 答:随便啦,想直接上传就直接上传,想打包成EXE就打包,看个人喜好. 19.如何理解.net的垃圾回收机制。 答:GC?对象创建了总要清除啊,不然内存哪够用?
全部16章220页 Asp.net教学讲义 1 讲义内容 6 第一章:asp.net和web窗体 6 1.1 NET应用开发架构简介 6 1.1.1. NET框架结构 6 1.1.2 http协议简介 6 1.1.3 静态网页与动态网页 8 1.1.4 客户端代码与服务器端代码 8 1.1.5 ASP.NET简介 8 1.2 Web 窗体与ASP.NET页面 8 1.2.1 简介 8 1.2.2 ASP.NET应用程序的创建方法 9 1.2.3 Web窗体的特点 10 1.2.4 Web 窗体的功能 10 1.2.5 WEB窗体工作原理 11 1.3 ASP.NET 页的结构 12 1.3.1 @Page指令 13 1.3.2 ASP.NET的服务器端脚本 14 1.3.3 服务器端脚本示例: 14 1.3.4 后台编码模型 15 1.4 Page事件(页面事件) 15 1.4.1 Page类 15 1.4.2 Web 窗体生命周期 16 1.4.3 Page事件 16 1.4.4 事件顺序 17 1.2.1.1 PageLoad事件 17 1.2.2 处理回送 18 1.2.2.1 回送使用示例 19 1.2.2.2 设置焦点 20 1.2.2.3 为Form设定默认按钮 21 1.2.3 ASP.NET应用程序示例 21 第二章:WEB服务器控件 23 2.1 WEB 服务器控件的格式 23 2.2 服务器控件的类型 23 2.3 用服务器控件建立页面 23 2.3.1 在设计界面上使用服务器控件高级编程) 24 2.3.2 在Source界面使用服务器控件 24 2.3.3 处理服务器控件的事件 24 2.4 控件的常见属性 25 2.5 控件的种类 26 2.5.1 标签、文本框 27 2.5.2 Button、ImageButton、LinkButton、HyperLink控件 27 2.5.3 选择控件 29 2.5.4 Panel和PlaceHolder控件 32 第三章:HTML控件和验证控件 35 3.1 HTML服务器控件简介 35 3.2 HTML服务器控件与Web服务器控件区别 37 3.3 ASP.NET的HTML服务器控件 38 3.3.1 HtmlForm控件 38 3.3.2 HtmlImage控件 40 3.3.3 InputFile控件 42 3.3.4 HtmlGenericControl 控件 43 3.4 ASP.NET2.0新增控件 45 3.4.1 ImageMap控件 45 3.4.2 FileUpload控件 48 3.5 客户端处理 52 3.5.1 第一种方式示例: 52 3.5.2第二种方式:动态注册javascript指令块 53 3.6验证控件 54 3.6.1验证控件简介 54 3.6.2必须字段验证控件 55 3.6.3 比较验证控件 56 3.6.4 范围验证控件 57 3.6.5正则表达式匹配验证控件 59 3.7自定义验证控件 62 3.8验证总结控件 64 第四章:ASP.NET内置对象 67 4.1内置对象概述 67 4.2 Response对象和Request对象 67 4.2.1 Response对象的功能,常用属性和方法和示例 67 4.2.2 Request对象的功能,常用属性和方法和示例 71 4.3、HttpServerUtility 对象 76 4.3.1 Execute方法和Transfer方法 76 4.3.2 HtmlEncode方法 77 4.3.3 UrlEncode方法 78 4.3.4 MapPath方法 79 第五章:ASP.NET状态管理 80 5.1 状态管理概述 80 5.2 存储状态的位置 80 5.3 Application—管理应用程序状态 80 5.4 应用程序事件 81 5.5 Lock和UnLock方法 81 5.6 添加、更新和移除Application状态项 81 5.7 Cookie 82 5.7.1 创建持久性Cookie对象 82 5.7.2 使用cookie的限制 82 5.7.3 利用cookie保存信息示例 83 5.7.4 使用cookie的缺点 84 5.8 Session—管理用户会话状态 84 5.8.1 Session的属性和方法 84 5.8.2 Session配置 85 5.8.3 session示例 85 5.9 计数器示例 87 5.10 Global.asax 89 5.11 使用Viewstate保持窗体状态 90 5.12 把视图状态用作数据存储 91 5.12.1 视图状态应用示例 92 5.13 利用查询字符串传递数据 92 5.14 利用隐藏的窗体字段传递数据 92 5.14 变量的作用域 93 第六章:站点设计 94 6.1 ASP.NET应用程序文件夹 94 6.2 母版页 96 6.2.1 母版页基础知识 96 6.2.2母版页运行机制 98 6.2.3 母版页的优点 100 6.3 创建母版页 100 6.4 创建内容页 102 6.5 皮肤和主题的概念 104 6.6 样式的应用 105 6.6.1 对单独页面元素使用样式 105 6.6.2 将样式移动到样式表 105 6.6.3 样式表编辑 105 6.7 主题的构成与构建 106 6.8 设置站点级别的样式 107 6.9 站点导航 108 6.9.1站点地图 108 6.9.2 SiteMapDataSource控件 108 6.10 导航控件 109 6.10.1 SiteMapPath控件 109 6.10.2 SiteMapPath控件属性 109 6.10.3 Menu控件 110 6.10.4 Treeview控件(高级编程) 110 第七章:ASP.NET的安全性 111 7.3安全性的概念 111 7.4 ASP.NET安全性的类型 111 7.5 身份验证 111 7.5.1 实现基于表单的身份验证 112 7.6创建和配置应用程序服务数据库 115 7.6.1 使用网站管理工具管理用户和角色 116 7.6.2 授权的概念与创建访问规则 118 7.6.3 使用控件管理用户和角色 119 7.6.4 成员资格和角色管理API编程 123 7.6.4.1 成员资格API概述 123 7.6.4.2 角色管理API概述 123 7.6.5 创建、修改、获取和删除用户 123 7.6.6 验证和解锁用户 125 7.6.7 角色管理 126 7.6.8 角色验证 127 7.6.9 其他重要成员 128 第八章:数据绑定 129 8.1 DataBinding概念 129 8.2 数据绑定的语法 129 8.3 DataBind()方法 129 8.4 单值数据绑定 129 8.5重复值数据绑定控件 132 8.6 绑定控件的通用属性介绍 132 8.6.1 列表控件 133 8.6.2 DataBind方法 134 8.6.3 示例1:BrowseCust.aspx 134 8.6.4 重复值数据绑定语法 136 8.6.5 模板的概念 136 8.6.6 Repeater控件 136 第九章:SQLDataSource控件与DataList 139 9.1 数据源控件简介 139 9.2 SqlDataSource控件 139 9.3 示例 141 9.4 添加Insert、Update和Delete语句 143 9.5 DataList控件 144 9.5.1 使用DataList浏览数据 144 9.5.2 使用DataList编辑数据 147 第十章:数据绑定控件(一) 152 10.1 GridView 152 10.1.1 手工配置DridView与定制列 156 10.1.2 实现分页 156 10.1.3 设置排序 157 10.1.4 GridView的字段类型 157 10.1.5 使用CommandField实现数据更新 157 10.1.6 使用hyperlinkField 159 10.1.7 使用ButtonFiled字段 161 10.1.8 使用ButtonField按钮字段 161 10.2 DetailView控件 163 10.2.1 定制DetailView的显示 163 10.2.2 联合使用DetailsView和GridView 163 10.2.3 使用DetailsView插入、更新和删除数据 165 第十一章:数据绑定控件(二) 166 11.1 FormView控件 166 11.1.1 使用FormView进行编辑当前记录 169 11.1.2 双向绑定语法 170 11.1.3 插入记录 170 11.1.4 相关的事件 170 11.2 ObjectDataSource控件 171 11.2.1 技术内幕 171 11.2.2 实现数据检索示例 172 11.2.3 使用参数 174 第十二章:用户控件和自定义控件 176 12.1 用户控件和自定义控件概述 176 12.2 什么时候使用用户控件 176 12.3 创建用户控件 176 12.4 创建自定义控件 178 第十三章:配置和错误处理 184 13.1 ASP.NET应用程序配置 184 13.2 配置文件结构 184 13.3 配置层次结构 185 13.4 配置元素 186 13.4.1 <configuration> 186 13.4.2 <configSections> 186 13.4.3 <appSettings> 186 13.4.5 <compilation> 187 13.4.6 <customErrors> 187 13.4.7 <sessionState> 188 13.4.8 <trace> 188 13.4.9 <authentication> 189 13.5 自定义应用程序设置的配置和检索 189 13.5.1 <appSettings> 190 13.5.2 自定义标记 190 13.6 使用管理工具 190 第十四章:跟踪、缓存、部署 193 14.1 跟踪简介 193 14.2 页面级跟踪 193 14.3 应用程序级跟踪 195 14.4缓存 196 14.4.1页面输出输出缓存 196 14.5 使用页面输出缓存API 197 14.6 数据缓存 198 第十五章:创建Web服务 201 15.1 Web服务简介 201 15.2 Web服务 201 15.3 Web服务的特征 201 15.4 Web服务体系结构 202 15.5 Web服务协议栈 202 15.6 使用.net2005创建Web服务 203 15.7 创建自定义的Web服务 205 15.8 使用自定义的Web服务 207 第十六章:WEBPARTS 209 16.1 Web部件基本知识 209 16.2 门户组件 209 16.3 创建最简单的门户网页 210 16.4 显示模式 213 16.5 目录部件和区域 214 16.6 属性 216 16.7 编辑器部件和区域 218 16.8 格式化Web部件和区域 220

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值