asp.net c# MVC:没有 ViewState 我该如何生活?
Posted
技术标签:
【中文标题】asp.net c# MVC:没有 ViewState 我该如何生活?【英文标题】:asp.net c# MVC: How do I live without ViewState? 【发布时间】:2011-01-14 21:20:55 【问题描述】:我正在研究将 WebForms 转换为 MVC:
在 .net MVC 中,哪些概念使 ViewState 成为不需要的东西?
如果表单被回发到自身等(即回发)?页面/用户控件如何维护其状态?
人们正在采取什么技巧来维持某种状态而不诉诸会话状态?
当然,不能存在完全无状态的环境?
【问题讨论】:
我确实意识到网络是无状态的,我的意思是与 asp.net webforms 相比...... 【参考方案1】:当然可以。事实上,网络是无状态的。事实上,任何相反的想法都是反常的。
Web 控件在 MVC 中消失了。服务器端没有触发事件。这被两种不同的机制所取代——URL 和 POST 表单数据。正确使用这些将取代您对 ViewState 的需求。
在传统的 ASP.NET Web 应用程序中,您可以在网页上放置一个 LinkButton,该按钮将执行 X 功能。ASP.NET 会将大量 ViewState 杂乱无章、javascript 和其他内容粘贴到网页中,以便当用户点击在按钮上并“回传”到网站(通过提交一个没人知道存在的表单),ASP.NET 重建发生的事情并确定必须执行特定的按钮事件处理程序。
在 MVC 中,您构建链接以访问特定路由。该路由描述了用户希望做什么——/Users/Delinquent/Index(显示所有拖欠用户的列表)。 MVC 中的路由系统确定哪个控制器将处理此路由以及该控制器上的哪个方法将执行。任何附加信息都可以通过 URL 查询字符串值(?Page=5 表示第 5 页的拖欠)传输到控制器方法。
除了 URL,您还可以使用 html 表单回传更复杂的信息(例如表单的数据价值)或不适合查询字符串的内容,例如文件。
因此,您可以通过查询字符串和表单 POST 值“维护”状态。你会发现,事实上,最终没有那么多状态需要维护。事实上,必须保持大量状态是一个很好的迹象,表明您的设计缺乏或者您正在尝试做一些不适合网站模型的事情。
【讨论】:
非常同意——只是没有必要,事实上,没有它会容易得多。 您网站的状态越少,编码、测试和维护就越容易。问题是状态是如此巨大的拐杖,一开始很难摆脱它。 +1 表示无状态视图层是好的设计。无状态视图被广泛误解。 已经研究 MCV 大约一个月了,这一切都说得通。这确实意味着重新实现一些东西,但从长远来看,节省的效率是巨大的。感谢您的回答.. 这个答案不是 100% 准确的,视图状态/维护状态不必与 asp.net“webforms”事件做任何事情。按钮点击例如postback 将在没有 viewstate 的情况下工作,您可以选择使用 viewstate 和/或选择性地禁用它,并且仍然使用用户控件、事件驱动模型和 asp.net webforms 带来的其他好处。事实上,即使以“webforms”实现的方式维护状态通常也很有用,尤其是在复杂的管理屏幕/页面中。 MVC 不是灵丹妙药;)【参考方案2】:一些相关问题:
Maintaining viewstate in Asp.net mvc? ASP.NET MVC doesn't work with ViewState and Postback?在大多数传统网络语言中,有状态环境的概念实际上并不常见。 ASP.NET Webforms 是该规则的一个例外,它通过重新发明许多标准来创建该例外。 Webforms 背后的目标本质上是抽象 HTML 和 Web 开发的概念,以便从开发的角度来看桌面应用程序和 Web 应用程序之间的界限变得模糊。这通常意味着 ASP.NET Webforms 提供的解决方案虽然有效,但它是一种万事通的实现,它会产生一些非常冗长的输出,足以满足大多数人的要求。相反,ASP.NET MVC 的核心优势在于它将 HTML 输出控制权交还给开发人员,并允许他们创建强架构的RESTful Web 应用程序,这些应用程序在实现和呈现方面定义得更好,更简洁——尽管牺牲了一些方便程度。
可以说,Webforms 模型的最大缺点之一是 ViewState,因为它会使输出变得混乱,在某些情况下会显着增加页面大小,并且通常相当于使用手提钻挂图片。与其尝试在 MVC 应用程序(或任何类似的东西)中使用 ViewState,不如开始使用显式控制表单中的字段并仅使用最相关的数据优化输入和输出操作的模式。除了标记的变化之外,您还将学习构建设计更好的解决方案,这些解决方案可以在您的应用程序内部和外部公开。
我喜欢做的第一个比较很简单:Webforms 构建网页,而 MVC 构建 Web 应用程序。如果您的日常工作主要是构建网站的各个部分,或者添加小块功能,您通常会发现 Webforms 更容易且耗时更少;另一方面,如果您想构建一个可测试、可扩展且灵活的完整应用程序,MVC 就是您的选择。
【讨论】:
【参考方案3】:viewstate 只是一个又大又丑的隐藏表单域。
写出您自己的隐藏表单字段,并在必要时对其进行加密。
幸运的是,不再有任何简单的方法可以将大量数据转储到页面中,因此您必须谨慎选择要保存的内容。
【讨论】:
加密?默认情况下不加密。你的意思是编码。您可以轻松解码视图状态。 @steven 你是对的,它并不总是加密的:msdn.microsoft.com/en-us/library/aa479501.aspx【参考方案4】:如果表单本身被回发等 (即回发)?怎么样 页面/用户控件保持其状态?人们正在采取什么技巧来维持某种状态而不诉诸会话状态?
已发布的 ViewData(或绑定到页面的强类型对象)可以再次推送到视图。请参阅this page. 中的“将验证和业务规则逻辑与模型类集成”,它展示了如何发布表单、对其进行验证以及在发生错误时将字段返回到表单。
.net MVC 中的概念是什么 ViewState 不是的东西 需要吗?
Representational State Transfer (REST).
【讨论】:
【参考方案5】:MVC 比 WebForms 有一些优点,但也有一些缺点,正如我在 this answer 中介绍的细节一样。我认为您必须问自己的基本问题是 ViewState 现在对您来说是否是一个问题 - 这是一个您必须重写您的应用程序的问题吗?如果不是,那么学习 MVC 是一个有价值的目标(这真的很酷),但不是我愿意冒险去做的目标。
话虽如此,ViewState 实际上可以在数量惊人的情况下被禁用。它主要用于通过回发保持控件的值。因此,例如,如果您有一个文本框,您必须在服务器端检查其值以及一堆其他字段,ViewState 将让您处理回发,捕获错误(并显示标签)然后将用户返回到所有条目都完好无损的表单。但是,如果表单仅会被填写并发回,然后您将被重定向到另一个页面,您可以安全地禁用它。
最后,你问人们正在做什么来避免会话状态。是否有理由避免会话状态?当然,您不需要太多信息,但完全没有必要完全避免它,事实上,这会让您失去武器库中最强大的工具之一。
【讨论】:
【参考方案6】:所有关于 ASP.NET MVC 不使用状态的答案都非常正确。但是 ASP.NET MVC 实际上确实使用了一些状态,尽管它不像 ViewState 那样工作。
通常,当有人向您的应用程序发布数据时,您会想要验证数据并在数据无效时显示错误。但是,如果你只是立即返回包含错误信息的页面,当用户按 F5 重新加载页面时,数据将被重新提交。这通常不是您想要的。因此,当您意识到 POST 的数据无效时,您想告诉用户获取该页面(或者可能是另一个页面)并显示错误消息。您可以通过返回 HTTP 重定向状态代码来实现。但是,一旦用户的 GET 请求进来,你怎么知道要显示什么错误信息呢?从您(服务器)处理 POST 到处理 GET,您必须以某种方式记住这一点。
为此,您使用名为 TempData 的 ASP.NET MVC 功能。这实际上只是 Session 的一个包装器,可确保您放入 TempData 字典中的任何内容都将保留在那里,直到下一个请求并且不再存在。
【讨论】:
+1 没有“宗教”的旧帖子。对于我们这些技术人员来说,订阅一些 uber 模型很容易 - 当然,直到它击中 用户。我很想看到一个“无国籍应用程序”,它会引导您完成纳税。更简单 - 只需自定义产品 + 结帐流程以及两者之间存在的任何导航如何。【参考方案7】:请考虑这样一个事实,即 Web 编程中的 REST 运动是基于状态对程序坏的想法。***有一个不错的描述和参考:http://en.wikipedia.org/wiki/Representational_State_Transfer
来自传统的 ASP.NET 和它提供的丰富事件模型,MVC 可能非常不和谐。它确实需要管理一些你以前看不到的东西,但我认为在可测试性方面的价值(REST 页面可以轻松触发,而无需创建复杂的视图状态,并且根据定义,服务器不是保持状态,以便我可以单独测试页面/功能)抵消了学习曲线。
有关 ASP.NET 和 REST 中的 MVC 的一些讨论:http://blog.wekeroad.com/2007/12/06/aspnet-mvc-using-restful-architecture/
【讨论】:
【参考方案8】:状态是数据库中的模型。您可以仔细缓存数据库以减少页面加载时间。
【讨论】:
【参考方案9】:MVC 中不存在自动生成的视图状态,但您可以简单地使用隐藏字段编写自己的视图,
在 MVC 中,您不会在页面顶部看到很多您不需要的加密字符。
【讨论】:
【参考方案10】:确实如此。您必须忘记持久性是由视图状态构成的。
您还必须在脑海中将回发转换为页面以“调用控制器”。这样以后事情会更容易理解。您调用的是返回视图的控制器,而不是调用 page 。因此,您要么在每次通话中一次又一次地构建您的整个“页面”,要么您决定只处理受该操作真正影响的内容。如果按钮正在更改 div,为什么要重新加载整个页面。只需让您调用控制器并返回 div 中的新数据即可。
例如,让我们想象一个主/细节场景:
<h2>Groups</h2>
<div id="GroupList">
</div>
<div id="GroupDetail" title="Detail Group">
</div>
组列表在 div 中加载一次,然后 是否可以对组列表中的每个项目的控制器进行 ajax 调用:
<%= Ajax.ActionLink("Edit", "DetailLocalisationGroup",
new id = group.Id ,
new AjaxOptions()
UpdateTargetId = "DetailLocalisationGroup",
OnSuccess = "InitialisationDetailGroup" )%>
调用这个动作 DetailLocalisationGroup 来为 div GroupDetail 提供 html。
[AcceptVerbs("POST")]
public ActionResult DetailLocalisationGroup(int id)
LocalisationGroup group = servicelocalisation.GetLocalisationGroup(id);
return View("DetailGroup", group);
现在 div 中有一个表单,当按下这个表单的提交按钮时,我们只是将我们真正需要的信息发送到控制器,然后控制器会将数据保存到数据库中。
在所有这些事件中,GroupList 充满了显示在客户端屏幕上的内容,但那里不需要交互,所以为什么要为这些事件的视图状态烦恼...
【讨论】:
嗨,好的,我正在阅读一些教程,并认为我明白你在说什么......但是不明白如何在没有 UI 上的模板布局设计的情况下列出内容,做您必须在控制器中硬编码某种 Html 模板吗?这似乎不像是关注点分离? 希望还为时不晚...好吧,控制器中不需要 Html 模板。您唯一需要做的就是说出要使用哪个视图,并为该视图提供它需要的对象。它的工作方式与用户控件相同。【参考方案11】:您可以使用MVC3Futures project 模拟视图状态。它会将整个模型保存在视图中。
您所要做的就是序列化模型并在视图中对其进行加密。
@Html.Serialize("Transfer", Model, SerializationMode.EncryptedAndSigned)
并在控制器中添加反序列化属性。
public ActionResult Transfer(string id,[Deserialize(SerializationMode.EncryptedAndSigned)]Transfer transfer)
【讨论】:
【参考方案12】:阅读完所有这些帖子后,听起来 MVC 不适用于 LOB 类型的应用程序,在这种应用程序中您将拥有大量控件和 CRUD 操作,并且您希望维护控件的状态。您希望用户在提交操作完成后保持相同的视图并保持状态的原因有很多。例如显示错误、服务器端验证消息、成功消息或执行任何其他操作。将用户重定向到其他视图以显示这些消息是不切实际的。
【讨论】:
【参考方案13】:您可以在会话状态中存储任何对象。
HttpContext.Session["userType"] = CurrentUser.GetUserType();
【讨论】:
以上是关于asp.net c# MVC:没有 ViewState 我该如何生活?的主要内容,如果未能解决你的问题,请参考以下文章
如何使 Angular POST 到 C# Asp.Net MVC 控制器?
请参阅 C# 中的 ASP.NET MVC 索引页面,使用 URL 中没有 ID 的模型中的数据填充