假设我有一个Web应用程序实现为一组向导页面来编辑复杂对象。在用户单击“完成”按钮之前,对象不会保存到后端系统(需求),因此在此期间我必须在某种会话状态下保留有关对象的全部信息
此外,某些向导页面必须显示可能包含大量项目的组合框和列表框。这些项目是使用Web服务从后端系统获取的。
巧合的是,该向导允许用户从一个向导页面自由跳转到任何其他页面(使用表单顶部的标签链接),因此它不是一个简单的“下一个,下一个......完成”的事情。
附加约束:Web应用程序在Web场上运行,客户厌倦了使用服务器端会话状态。在最好的情况下,他们希望将会话状态的大小保持最小(过去他们遇到了这个问题)。
所以基本上这里有两个问题:
我正在考虑的选项:
将对象存储在类似WebForms的 ViewState 中(通过将其序列化到HTML页面中)。这还包括组合框项目。显然,HTML页面可能会变得非常大,因此Web应用程序会很慢。
将其存储到服务器端会话状态,无论客户的意愿如何,并且在实际Web场上测试之前不知道性能将如何受到影响(项目后期) )。
我无法在两者之间做出决定。或者还有另一种选择吗?
答案 0 :(得分:5)
为什么要缓存?您可以只使用选项卡页面,其中每个页面都是div或面板,只显示与选项卡相关的当前div。这样,当用户提交表单时,您无需跟踪和处理所有输入。
答案 1 :(得分:3)
是否可以将向导数据存储在数据库的临时表中?当用户完成向导时,将从临时表中复制数据并将其删除。临时表包含一个时间戳,用于删除任何旧的未完成数据。
答案 2 :(得分:2)
正如Daisy所说,它不一定要被缓存。您还可以使用隐藏的表单字段。因为这些可以映射到每个控制器操作上的相同对象,所以可以通过连续的页面逐步构建对象。
//Here's a class we're going to use
public class Person
{
public int Age {get;set;}
public string Name {get;set;}
public Person()
{
}
}
//Here's the controller
public Controller PersonCreator
{
public ActionResult CreatePerson()
{
//Posting from this page will go to SetPersonAge, as the name will be set in here.
return View();
}
public ActionResult SetPersonAge(Person person)
{
//This should now have the name and age of the person
return View(person);
}
}
//Here is your SetPersonAge, which contains the name in the model already:
<%= Html.Hidden("Name", Model.Name) %>
<%Html.TextBox("Age") %>
这就是它。
答案 3 :(得分:1)
我可以建议更多选项
将整个向导作为单个页面,并在客户端通过javascript显示和隐藏内容。这可能会导致初始页面加载速度变慢。
使用缓存应用程序块(或类似的东西)缓存服务器上的数据。这将允许所有用户共享此数据的单个实例,而不是在所有会话中复制。现在数据更轻,您可以说服客户允许在会话中存储。
答案 4 :(得分:1)
MVC社区对使用Sessions存在很多阻力。问题是我们很多开发人员正在构建像银行网站这样的登录系统。有人可能会争论隐藏的字段并且适用于某些情况,但是当我们需要为用户提供安全性和合规性时,那么您有几种选择。 Cookies不可靠。依赖于Javascript计时器是不可靠的,并且不符合508标准,因为目标应该是优雅地降级。因此,对于登录,会话是一个不错的选择。如果将时间写入客户端浏览器,服务器数据库或服务器文件系统,则仍需要管理每个用户的时间。
因此谨慎使用Sessions,但不要害怕它们。对于向导,您在技术上可以序列化传递它们的隐藏字段。我怀疑需求和范围将变得更大,使用Sessions的授权/身份验证实现将成为应用程序的关键。
答案 5 :(得分:1)
如果你不能使用ajax(用于验证和下拉菜单以及将向导转换为标签页的能力)并且不能使用html5(用于下拉缓存和在本地存储中保存表单状态),那么我认为你已经非常可用了“最好的做法“你必须诉诸坏(或更糟)的。
由于MVC是关于会话使用的WebForms的反对者,也许您可以使用解决方法?例如,除了将所有这些值存储在某些临时数据库记录中之外,您需要稍后进行清理,您可以为Windows Server设置AppFabric extension并使用它来存储下拉列表项(并且范围可以适用于所有用户,因此如果更多用户同时使用系统,则只需要一次调用Web服务来刷新缓存),并且还可以在步骤之间临时存储对象。您可以在AppFabric中将临时对象设置为自动过期,因此无需进行清理。如果您通过Web服务广泛地调用另一个系统,它对于加速系统的其他部分也会有所帮助。
答案 6 :(得分:0)
我一直在处理同样的问题,虽然我的要求稍微简单一些(只保留几个字符串的状态),但我的解决方案可能适合您。我也有兴趣听听别人对这种方法的看法。
我最终做的是:在控制器中我只是将我想要的数据转储到Controller的Session属性中,然后在我需要它时将其拉出来。对于你的情况,这样的事情是这样的:
//Here's the controller
public Controller PersonCreator
{
public ActionResult CreatePerson()
{
//get the age out of the session
int age = (int)(Session["age"]);
//do something with it...
return View();
}
public ActionResult SetPersonAge(Person person)
{
//put the age in the session
Session.Add("age", person.Age);
return View(person);
}
}
我喜欢这个是我不必在我的视图页面上放置一堆隐藏的参数。
答案 7 :(得分:0)
答案可以在Steve Sanderson's ASP.NET MVC 2/3中找到,并且需要参考MVC Futures集合。这个Google Books链接正是他所做的。
实质上,您将向导数据序列化到View。呈现隐藏字段,存储所有获取的信息。
您的控制器可以通过使用OnActionExecuting
和OnResultExecuted
(以满足重定向)将其传递到下一个视图来确定要执行的操作。
阅读 - 他解释得比我更彻底。