WebForms 中的对象是否持久存在于内存中?
Are objects in WebForms persistent in memory?
我对 C# 有很多经验,但我对 WebForms 还很陌生。
我正在做一个项目,其中大量数据存储在 ViewState 中,但我不明白为什么。
我的理解是表示我的页面 (System.Web.UI.Page) 的对象在该页面的生命周期内是持久的。在 ViewState 中存储标识符可能有一些幕后魔法,但是当对该页面上的事件做出反应时,我不能简单地引用 "this" 及其 properties/methods 吗?
我什么时候会明确地将数据存储在 ViewState 中,而不是简单地使用当前对象(在本例中为页面)的属性?
--雅各布
My understanding is that the object representing my Page (System.Web.UI.Page) is persistent for the life of that Page
这是正确的,但是页面的生命周期仅适用于单个请求,在 HTML 已交付给客户端后,Page
实例将被销毁。
我推荐阅读这篇文章:https://msdn.microsoft.com/en-us/library/ms178472.aspx
请注意,WebForms 的设计:将 无状态网络 抽象为类似 WinForms 的伪状态环境在很大程度上被认为是错误的,这就是为什么 ASP.NET MVC 和 ASP.NET Core 具有截然不同的设计(尽管 Controller
实例可以与 Page
实例进行比较,具有相似的生命周期语义但开销要少得多)。
There may be some behind-the-scenes magic where an identifier is stored in ViewState, but when reacting to events on that page, can I not simply refer to "this" and its properties/methods?
我很难理解这一点 - 但如果您认为 Page
的所有实例成员,包括仅使用支持字段的自定义属性,都会在请求之间自动保留(包括 "postback" 请求) 那么不,那不是真的。字段没有神奇的持久性,您需要使用 Page.ViewState
属性 作为这些属性的后备存储,并且该数据仅在特殊的 "postback" POST 之间持久化请求。
让我尝试自己的解释:
- 浏览器请求
GET /MyForm.aspx
- ASP.NET 创建
MyForm : System.Web.UI.Page
的新实例,创建在 .aspx
文件中声明的所有子控件实例,并调用 Init
和 Load
所有控件上的事件,然后 Render
生成输出 HTML,然后 Unload
。该请求的 MyForm
实例随后被垃圾收集。
如果 MyForm.aspx
包含 <form runat="server">
并使用 "postback",则当用户执行某些操作触发回发时:
- 浏览器向
POST /MyForm.aspx
发出请求,其中请求正文是来自 <input >
元素的数据。在 HTML、 只有 的规则下 <input>
(以及 <select>
、<textarea>
等)的内容在 POST 请求而不是整个 DOM - 这是 ASP.NET WebForms 的一个问题,因为所有这些 Controls
都有许多属性和设置(例如 <asp:Label FontColor="">
没有持久化通过他们自己的 <input type="hidden" name="label123_FontColor">
,此外,即使他们有很多冗长的数据要发送回服务器。
因此,ASP.NET 指示所有 Control
实例将其所有非 <input>
数据序列化到 ViewState
字典(代表 [=67= View 的 ]state(按 MVP/MVC 的说法,.aspx
/HTML 是 View - 因此将其状态与根据定义是短暂的请求状态分开保存。
在 Control
或 Page
子类中,您需要使用 ViewState,而不是支持字段:
public String SomeName {
get { return this.ViewState["SomeName"] as String; }
set { this.ViewState["SomeName"] = value; }
}
...然后 ViewState
被序列化、压缩、签名并呈现到 <input name="__VIEWSTATE" type="hidden">
中的页面。
之所以在 __VIEWSTATE
中携带状态而不是简单地在每次页面请求时重新生成整个页面的数据,是因为有时最初生成页面可能涉及繁重的工作(例如数据库查询)。论据是,如果您有一个包含数据列表的页面,并且用户只是在将数据保存回数据库之前简单地操作该数据,那么您不需要从数据库重新加载,而是将该视图级数据存储在页面的 __VIEWSTATE
就好像它是某种超级 cookie 之类的东西。
我对 C# 有很多经验,但我对 WebForms 还很陌生。
我正在做一个项目,其中大量数据存储在 ViewState 中,但我不明白为什么。
我的理解是表示我的页面 (System.Web.UI.Page) 的对象在该页面的生命周期内是持久的。在 ViewState 中存储标识符可能有一些幕后魔法,但是当对该页面上的事件做出反应时,我不能简单地引用 "this" 及其 properties/methods 吗?
我什么时候会明确地将数据存储在 ViewState 中,而不是简单地使用当前对象(在本例中为页面)的属性?
--雅各布
My understanding is that the object representing my Page (System.Web.UI.Page) is persistent for the life of that Page
这是正确的,但是页面的生命周期仅适用于单个请求,在 HTML 已交付给客户端后,Page
实例将被销毁。
我推荐阅读这篇文章:https://msdn.microsoft.com/en-us/library/ms178472.aspx
请注意,WebForms 的设计:将 无状态网络 抽象为类似 WinForms 的伪状态环境在很大程度上被认为是错误的,这就是为什么 ASP.NET MVC 和 ASP.NET Core 具有截然不同的设计(尽管 Controller
实例可以与 Page
实例进行比较,具有相似的生命周期语义但开销要少得多)。
There may be some behind-the-scenes magic where an identifier is stored in ViewState, but when reacting to events on that page, can I not simply refer to "this" and its properties/methods?
我很难理解这一点 - 但如果您认为 Page
的所有实例成员,包括仅使用支持字段的自定义属性,都会在请求之间自动保留(包括 "postback" 请求) 那么不,那不是真的。字段没有神奇的持久性,您需要使用 Page.ViewState
属性 作为这些属性的后备存储,并且该数据仅在特殊的 "postback" POST 之间持久化请求。
让我尝试自己的解释:
- 浏览器请求
GET /MyForm.aspx
- ASP.NET 创建
MyForm : System.Web.UI.Page
的新实例,创建在.aspx
文件中声明的所有子控件实例,并调用Init
和Load
所有控件上的事件,然后Render
生成输出 HTML,然后Unload
。该请求的MyForm
实例随后被垃圾收集。
如果 MyForm.aspx
包含 <form runat="server">
并使用 "postback",则当用户执行某些操作触发回发时:
- 浏览器向
POST /MyForm.aspx
发出请求,其中请求正文是来自<input >
元素的数据。在 HTML、 只有 的规则下<input>
(以及<select>
、<textarea>
等)的内容在 POST 请求而不是整个 DOM - 这是 ASP.NET WebForms 的一个问题,因为所有这些Controls
都有许多属性和设置(例如<asp:Label FontColor="">
没有持久化通过他们自己的<input type="hidden" name="label123_FontColor">
,此外,即使他们有很多冗长的数据要发送回服务器。
因此,ASP.NET 指示所有 Control
实例将其所有非 <input>
数据序列化到 ViewState
字典(代表 [=67= View 的 ]state(按 MVP/MVC 的说法,.aspx
/HTML 是 View - 因此将其状态与根据定义是短暂的请求状态分开保存。
在 Control
或 Page
子类中,您需要使用 ViewState,而不是支持字段:
public String SomeName {
get { return this.ViewState["SomeName"] as String; }
set { this.ViewState["SomeName"] = value; }
}
...然后 ViewState
被序列化、压缩、签名并呈现到 <input name="__VIEWSTATE" type="hidden">
中的页面。
之所以在 __VIEWSTATE
中携带状态而不是简单地在每次页面请求时重新生成整个页面的数据,是因为有时最初生成页面可能涉及繁重的工作(例如数据库查询)。论据是,如果您有一个包含数据列表的页面,并且用户只是在将数据保存回数据库之前简单地操作该数据,那么您不需要从数据库重新加载,而是将该视图级数据存储在页面的 __VIEWSTATE
就好像它是某种超级 cookie 之类的东西。