首页 技术 正文
技术 2022年11月9日
0 收藏 772 点赞 3,556 浏览 7213 个字

Application:所有的会话共享一个Application空间,任何一个人改变Application的内容,其他人都会发现被改变了。Application中的内容不会被自动释放

存放位置:服务端
所有的访问用户都是访问的同一个变量

(1)用Application存值:Application[“key名”] = 值; 值,不只是个字符串,可以是对象。

        string s = TextBox1.Text;
Application["aaa"] = s;

(2)用Application取值:类型 变量名 = (强制转换的类型名)Application[“key名”]

protected void Page_Load(object sender, EventArgs e)
{
if(Application["aaa"]!=null)
{
Label1.Text=(string)Application["aaa"];
// Label1.Text = Application["aaa"].ToString();
}
}

(3)判断Application中是否存有某个值
if(Application[“key名”] == null)
{

}
(4)释放Application:Application[“key名”] = null;

案例:每次访问页面都会累加访问次数

Webform Application传值  ViewStateWebform Application传值  ViewState

 protected void Page_Load(object sender, EventArgs e)
{
if (Application["count"] == null)
{
Application["count"] = 0;
}
Application["count"] = (int)Application["count"] + 1; Label1.Text = Application["count"].ToString();
}

Webform Application传值  ViewStateWebform Application传值  ViewState

隐藏的状态—ViewState探秘

1.1 从Http的无状态说起

  Http是一个无状态协议,同一个会话的连续两个请求互相不了解,它们由最新实例化的环境进行解析,除了应用本身可能已经存储在全局对象中的所有信息外,该环境不保存与会话有关的任何信息。另外,因为,浏览器和服务器之间是通过Socket进行通信,Http请求通常请求完毕就会关闭Socket连接,因此Http协议不会保持连接。如果保持连接会降低客户端并发处理请求数,不保持连接又会降低处理速度(建立连接所需的时间会长一点);

PS:这里我们可以这样来理解:假如我们去一个大型商场购物购买某个产品,第一次去的时候是A销售员接待了我们,带领我们来到XX产品的柜台并为我们推荐了XX产品;等我们回去使用XX产品后,觉得XX产品真心不错。第二次我们又去,但是这次却找不到上次那个A销售员了,相反商场分配了另一个B销售员来接待我们,他不知道我们上次选择了XX产品,相反它却一个劲地向我们推荐YY产品并把我们带向YY产品的柜台;这个时候,我们一般会说:我擦,把上次那个妹子给我叫来!

  基于Http协议的无状态特性,我们在ASP.Net的开发中也会经常碰到这种情况:用户上一次提交的东西,下次再提交时服务器就不记得了。很多时候,我们感到很不解?后来,我们发现原来每一次的请求服务器都开启了不同的线程来处理,也就是说每次都会new一个XXX.aspx.cs中的类对象实例来进行处理(上一次new出来为我们处理的page对象也许早就被服务器销毁了)。比如,我们在xxx.aspx.cs代码中写入了一个int类型的number成员(初始为0),每次请求我们都想让这个number自增一下,然后重新返回给浏览器。但就是这么一个简单的梦想,我们却无法轻易的实现。

 那么,到底怎么来破呢?大神们已经为我们想好了策略,我们可以使用隐藏域字段、Cookie、Session等来保存状态。而伟大的Microsoft还在ASP.Net中帮我们封装了ViewState,以至于我们在WebForm中进行PostBack操作时,都感觉不到服务器是无状态的。

1.2 青春四处绽放—无处不在的ViewState

  (1)类似于Dictionary的一种数据结构

  如果你曾经使用过Dictionary或者Session的话,那么你应该了解这种Key/Value的数据结构。这里并没有什么高深的理论,ViewState通过String类型的数据作为索引。ViewState对应项中的值可以存储任何类型的值(参数是Object类型),实施上任何类型的值存储到ViewState中都会被装箱为Object类型。

  例如,这里我们可以改写上面那个按钮事件中的代码:

 1 protected void btnGetNumber_Click(object sender, EventArgs e)
2 {
3 //number++;
4 //this.lblNumber.Text = number.ToString();
5
6 object age = this.ViewState["age"];
7 if (age == null)
8 {
9 age = 1;
10 }
11 else
12 {
13 age = Convert.ToInt32(age) + 1;
14 }
15 this.ViewState["age"] = age;
16 this.lblNumber.Text = age.ToString();
17 }

  这里,我们借助ViewState存储了age的状态值,第一次来我给你返回1,后面再来我就加1再返回给你。于是,在上一节我们所提到的那个问题(无法记住上次的number值,每次都返回1)就解决了。

PS:ViewState不能存储所有的数据类型,仅支持以下的这几种:
String、Integer、Boolean、Array、ArrayList、Hashtable以及一些自定义类型

  我们都知道,Dictionary和Session都是存储在服务器端的。那么,我们不禁要问,既然我们在服务器端给ViewState增加了一个Key/Value对,并返回给浏览器端,ViewState又是存储在什么位置的呢?

  (2)大隐隐于市的“页面级”隐藏字段

  跟Session和Dictionary的存储位置不同,ViewState的作用域是页面,也就是说ViewState是存储在浏览器的页面之中的(这里相比Session等,耗费的服务器资源较少,也算是ViewState的优点之一吧),当你关闭某个aspx文件后,那么属于这个aspx的ViewState也就不存在了。或许,这么说来,我们还不是很了解,现在我们来实地看看。

  ①首先,如果页面上有一个runat=”server”的form,当用户请求这个页面时,服务器会自动添加一个_ViewState的隐藏域返回给浏览器。但是,我们发现这个ViewState的value看起来像一串乱码?这是为什么呢?这是因为服务器在向浏览器返回html之前,对ViewState中的内容进行了Base64的加密编码

  ②其次,当用户点击页面中的某个按钮提交表单时,浏览器会将这个_VIEWSTATE的隐藏域也一起提交到服务端;服务器端在解析请求时,会将浏览器提交过来的ViewState进行反序列化后填充到ViewState属性中(比如下图中,我们可以通过一个软件将_VIEWSTATE解码得到一个如下图所示的树形结构);再根据业务处理需要,从这个属性中根据索引找到具体的Value值并对其进行操作;操作完成后,再将ViewState进行Base64编码再次返回给浏览器端;

  ③因此,我们可以得出一个结论:VIEWSTATE适用于同一个页面在不关闭的情况下多次与服务器交互(PostBack)。这里我们也可以通过下图来温习一下ViewState的流程,ViewState存放着“事故现场”,下次可以方便地“还原现场”,将无状态的Http模拟成了有状态的,也让广大的初学者了解不到无状态的这个特性。

1.3 喜欢就会放肆—又爱又恨的ViewState!

  事实上,除了我们手动在服务器端向ViewState属性中添加的K/V对数据,我们在aspx.cs代码中为某些服务器控件设置的值(例如:为Repeater设置DataSource中存入的数据集、为Label所设置的Text内容等,但不包括:TextBox、CheckBox、CheckboxList、RadioButtonList)都存入了ViewState中。这样做的话,我们下次再向服务器提交请求时,现有表单中所有的服务器控件状态都会记录在ViewState中提交到服务器,在服务器端可以方便地对这些服务器控件进行有状态的操作并返回,这无疑是让我们欢喜的,因为方便了我们的开发过程,提高了我们的开发效率;

  但有人说:“喜欢就会放肆”,ViewState让人又爱又恨啊。例如,在我们使用Repeater的过程中,WebForm会自动将DataSource(数据源,你可以理解为一个集合)存储到ViewState中并返回给浏览器。可以参考下面的例子来实地理解一下:

  ①含有Repeater的aspx页面:

 1     <form id="form1" runat="server">
2 <div align="center">
3 <table class="test">
4 <tr class="first">
5 <td>
6 ID
7 </td>
8 <td>
9 产品名称
10 </td>
11 <td>
12 产品描述
13 </td>
14 <td>
15 删除
16 </td>
17 </tr>
18 <asp:Repeater ID="repeaterProducts" runat="server">
19 <ItemTemplate>
20 <tr>
21 <td>
22 <%#Eval("Id") %>
23 </td>
24 <td>
25 <%#Eval("Name") %>
26 </td>
27 <td>
28 <%#Eval("Msg") %>
29 </td>
30 <td>
31 <a href='Product.ashx?Action=Delete&Id=<%#Eval("Id") %>'>删除</a>
32 </td>
33 </tr>
34 </ItemTemplate>
35 </asp:Repeater>
36 </table>
37 </div>
38 </form>

  ②后台代码模拟从数据库中取得数据集合并绑定到Repeater中:

 1 protected void Page_Load(object sender, EventArgs e)
2 {
3 if (!IsPostBack)
4 {
5 this.repeaterProducts.DataSource = this.GetProductList();
6 this.repeaterProducts.DataBind();
7 }
8 }
9
10 private IList<Product> GetProductList()
11 {
12 IList<Product> productList = new List<Product>();
13 productList.Add(new Product() { Id = 1, Name = "康师傅方便面", Msg = "就是这个味儿!" });
14 productList.Add(new Product() { Id = 2, Name = "统一方便面", Msg = "还是那个味儿!" });
15 productList.Add(new Product() { Id = 3, Name = "白象方便面", Msg = "大骨浓汤啊!" });
16 productList.Add(new Product() { Id = 4, Name = "日本方便面", Msg = "不只是爱情动作片!" });
17 productList.Add(new Product() { Id = 5, Name = "台湾方便面", Msg = "马英九夸我好吃!" });
18
19 return productList;
20 }

  编译生成后,通过查看此页面的html代码,可以明显看到一长串的_VIEWSTATE隐藏域。将此_VIEWSTATE复制到ViewStateDecoder中进行反编码,可以发现它确实存储了Repeater中的数据集合。这里我们不禁要问:展示数据既然已经渲染成了html,为何还要存储在ViewState隐藏域中?如果我们的数据集合是一百行、一千行数据的话,那ViewState隐藏域岂不很大(100k?200k?)?但不幸的是,这是ViewState的设计机制,要想依靠它来保持状态,它就会将服务器控件的状态包括数据集合都存储到其中,在浏览器和服务器之间来回传递保持状态。

  这里就涉及到网站的性能问题的探讨了:由于ViewState存储在页本身,因此如果存储较大的值,用户请求显示页面的速度会减慢(这对于互联网系统来说,就是一个噩梦。你会选择一个1秒内响应的网站浏览还是5秒内响应的网站?)。又因为ViewState会随同Form表单一同回传给服务器,如果ViewState很大的话,Http报文也会很大,网站流量消耗也会增大。

  那么,有没有一种方法可以让ViewState克制一下呢?别急,请看下面的介绍。

1.4 但爱就是克制—禁用还是不禁用ViewState?

  刚刚说到,因为ViewState会一定程度上影响性能,所以我们可以在不需要的时候禁用 ViewState。默认情况下 ViewState 将被启用,并且是由每个控件(而非页面开发人员)来决定存储在 ViewState 中的内容。有时,这一信息对应用程序并没有什么用处(例如上面提到的Repeater的数据集合,已经渲染生成了html显示,还存储了一份副本在ViewState里边)。尽管也没什么害处,但却会明显增加发送到浏览器的页面的大小。因此如果不需要用ViewState,最好还是将它关闭,特别是当 ViewState 很大的时候。当然,ViewState帮我们实现了某些服务器控件状态保持,因此在非必需的情况下,还是可以适度使用的,特别是在开发企业内部信息系统的场景。

  那么,怎样来禁用ViewState呢?禁用ViewState又有什么策略呢?下面我们一一来探讨。

  ①页面级禁用ViewState:在aspx的首部的Page指令集中添加EnableViewState=”false”,该页面中所有控件的状态都不会存入ViewState的,页面一下就会清爽许多;

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="RepeaterViewState.aspx.cs"
Inherits="WebFormDemo.RepeaterViewState" EnableViewState="false" %>

  禁用后,再次查看生成的html代码,我们会发现:咦,_VIEWSTATE还在那儿,但是明显比先前的体积小了不少

  再将这个瘦身后的_VIEWSTATE复制到ViewStateDecoder中进行反编码查看,我们会发现,只保存了一个最基本的信息,Repeater的那些数据集合没有存入进去了。

PS:为什么禁用ViewState之后,页面源代码中仍然有_VIEWSTATE的隐藏域

这是因为就算禁用了viewstate,aspx页面中还是会有一个服务器控件在那里使用,这就是<form runat=”server”>。这时,如果你将form去掉runat=”server”,将其变为普通html标签,那么页面就干净了,从此_VIEWSTATE这个隐藏域彻底消失在你的页面中。

  ②控件级禁用ViewState:在某些场景中,我们只希望禁用某个控件(例如Repater)的ViewState,其他控件仍然通过ViewState保持状态。这时,我们可以给指定的控件设置一个属性EnableViewState=”false”即可;

<asp:Repeater ID="repeaterProducts" runat="server" EnableViewState="false">
</asp:Repeater>

  ③全局级禁用ViewState:园子里的大神老赵(Jeffrey Zhao)曾经说过,“我如果新建一个WebForm项目,做的第一件事情就是去Web.config中将enableViewState设置为false从而将ViewState全局关闭”。那么,我们如果希望将网站中所有页面的ViewState都禁用,总不可能去一个一个页面得修改Page指令吧?ASP.Net为我们提供了一个配置,我们只需要在Web.config的system.web中增加一句配置即可:

<pages enableViewState="false" />

PS:开发中也可以采用大神老赵的做法,先禁用,再选择性启用,毕竟没有非要ViewState才能干成的事儿!

  ④真正的禁用ViewState:刚刚我们的三种方法实践后,在页面还是出现_VIEWSTATE的隐藏域,尽管它保留了最基本的信息。那么,我们可能会问?怎样才能彻底地真正地禁用ViewState,根本就别给我生成_VIEWSTATE的隐藏域。答案是有的,将<form runat=”server”/>的runat=”server”去掉,就不会出现了,但那样又会偏离WebForm的开发模式,大部分的服务器控件都无法正常使用,开发效率又会有所损失。

  综上所述,在实际开发中应该权衡利弊,特殊情况特殊分析(到底这个场景该不该禁用ViewState),选择是否禁用ViewState,采用何种方式禁用ViewState。对于ViewState的探秘本篇就到此为止,由于我本人理解的也不是很深刻,所以希望各位园友如果有理解,可以回复出来大家探讨共同进步。

 

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,964
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,486
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,331
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,114
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,747
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,781