我对c#有很多经验,但我对WebForms还不熟悉。
我正在开发一个项目,其中大量数据存储在ViewState中,我不明白为什么。
我的理解是,表示我的Page(System.Web.UI.Page)的对象在该页面的生命周期内是持久的。可能存在一些幕后魔术,其中标识符存储在ViewState中,但是当对该页面上的事件作出反应时,我不能简单地参考"这个"及其属性/方法?
我何时将数据显式存储在ViewState中,而不是简单地使用当前对象的属性(本例中为Page)?
- 雅各布
答案 0 :(得分:1)
我的理解是,表示我的Page(System.Web.UI.Page)的对象在该页面的生命周期内是持久的
这是正确的,但是在将HTML传递到客户端之后,页面的生命周期仅针对单个请求,然后Page
实例被销毁。
我建议您阅读这篇文章:https://msdn.microsoft.com/en-us/library/ms178472.aspx
请注意,WebForms的设计:将 stateless-web 抽象为伪状态类WinForms环境在很大程度上被认为是一个错误,这就是ASP.NET MVC和ASP.NET Core的原因所在。一个完全不同的设计(尽管Controller
个实例可以与Page
实例进行比较,具有相似的生命周期语义,但开销却相当低。)
可能存在一些幕后魔术,其中标识符存储在ViewState中,但是当对该页面上的事件作出反应时,我是否可以简单地引用“this”及其属性/方法?
我很难理解这一点 - 但如果您认为Page
的所有实例成员(包括仅使用支持字段的自定义属性)会自动保留在请求之间(包括“回发”请求),那么不,这不是真的。字段没有魔术持久性,您需要使用Page.ViewState
属性作为这些属性的后备存储,并且该数据仅在特殊的“回发”POST请求之间保留。
让我尝试自己的解释:
GET /MyForm.aspx
MyForm : System.Web.UI.Page
的新实例,创建在.aspx
文件中声明的所有子控件实例,并调用所有Init
和Load
个事件控件,然后Render
生成输出HTML,然后Unload
。然后,请求的MyForm
实例被垃圾收集。如果MyForm.aspx
包含<form runat="server">
并使用“回发”,则当用户执行触发回发的操作时:
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
字典(代表 state View (用MVP / MVC的说法,.aspx
/ HTML 是视图 - 因此将其状态与请求状态分开,其中by-definition是短命)。
在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
中携带而不是简单地在每个页面请求上重新生成整个页面的数据是因为有时最初生成页面可能涉及繁重的提升(例如,DB查询)。这个论点是,如果你有一个包含数据列表的页面,并且用户只是在将数据保存回数据库之前操作该数据,那么你不需要从数据库重新加载,而是将该视图级数据存储在数据库中。页面__VIEWSTATE
,好像它是某种超级cookie或其他东西。