ASP.NET MVC:在类似向导的应用程序中保持会话状态的最佳实践

发布于 2024-07-30 11:36:08 字数 776 浏览 7 评论 0原文

假设我有一个像一组向导页面一样实现的 Web 应用程序来编辑复杂的对象。 在用户单击“完成”按钮之前,对象不会保存到后端系统(要求),因此与此同时,我必须将有关对象的全部信息保留在某种会话状态中。

此外,某些向导页面必须显示可能包含大量项目的组合框和列表框。 这些项目是使用 Web 服务从后端系统获取的。

巧合的是,该向导允许用户自由地从一个向导页面跳转到任何其他页面(使用表单顶部的选项卡链接),因此这不是一个简单的“下一步,下一步...完成”的事情。

附加约束:Web 应用程序在 Web 场上运行,并且客户厌倦了使用服务器端会话状态。 在最好的情况下,他们希望将会话状态的大小保持在最小(他们过去在这方面遇到过问题)。

所以基本上这里有两个问题:

  1. 如何/在哪里保存用户在向导中输入的数据?
  2. 是否缓存从后端接收到的组合/列表项,如果是,在哪里?

我正在考虑的选项:

  1. 将对象存储在类似 WebForms 的 ViewState 中(通过将其序列化到 HTML 页面中)。 这还包括组合框项目。 显然,HTML 页面变得非常大可能会出现问题,因此 Web 应用程序会很慢。

  2. 将其存储到服务器端会话状态中,无论客户的意愿如何,也不知道性能将如何受到影响,直到在实际的网络场上进行测试(项目后期)。< /p>

我无法在两者之间做出决定。 或者还有其他选择吗?

Let's say I have a Web application implemented like a set of wizard pages to edit a complex object. Until the user clicks on the "Finish" button, the object doesn't get saved to the back-end system (a requirement), so in the meantime I have to keep the whole information about the object in some kind of a session state.

Also, some of the wizard pages have to show combo and list boxes with potentially large number of items. These items are fetched from the back-end system using a Web service.

Coincidentally, the wizard allows the user to freely jump from one wizard page to any other (using tab links on top of the form), so it's not a simple "next, next... finish" thing.

Additional constraint: the Web application runs on a Web farm and the customer is weary of using server-side session state. In the best case they want to keep the size of the session state minimal (they had problems with this in the past).

So basically there are two problems here:

  1. How/where to keep data entered by the user in the Wizard?
  2. Whether to cache the combo/list items received from the back-end and if so, where?

Options I'm considering:

  1. Storing the object in a WebForms-like ViewState (by serializing it into the HTML page). This would also include the combo box items. Obviously, there could be a problem with HTML pages becoming very large and thus Web application will be slow.

  2. Storing it into server-side session state, regardless of the customer's wishes and without knowing how the performance will be affected until it is tested on the actual Web farm (late in the project).

I cannot decide between the two. Or is there another alternative?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

蝶舞 2024-08-06 11:36:08

为什么要缓存? 您可以只拥有选项卡式页面,其中每个页面都是一个 div 或面板,并且只显示与选项卡相关的当前 div。 这样,当用户提交表单时,您就不必跟踪和处理所有输入。

Why cache at all? You could just have the tabbed pages where each page is a div or panel and just display the current div relating to your tab. That way you dont have to keep track and process all the inputs when the user submits the form.

寄人书 2024-08-06 11:36:08

是否可以将向导数据存储在数据库的临时表中? 当用户完成向导时,将从临时表中复制数据并删除。 临时表包含一个时间戳,用于删除任何旧的未完成数据。

Is it possible to store the wizard data in a temporary table in the database? When the user finishes the wizard the data is copied from the temporary table and deleted. The temporary table includes a timestamp to remove any old uncompleted data.

想你的星星会说话 2024-08-06 11:36:08

正如黛西所说,它不必被缓存。 您还可以使用隐藏的表单字段。 由于这些可以映射到每个控制器操作上的同一对象,因此您可以通过连续的页面逐步构建对象。

//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") %>

差不多就是这样了。

As Daisy said, it doesn't have to be cached. You could also use hidden form fields. Because these could map to the same object on each controller action, you could progressively build the object through successive pages.

//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") %>

And that's pretty much it.

源来凯始玺欢你 2024-08-06 11:36:08

我可以建议更多选项

  1. 将整个向导作为一个页面,其中选项卡通过客户端的 javascript 显示和隐藏内容。 但这可能会导致初始页面加载速度变慢。

  2. 使用缓存应用程序块(或类似的东西)在服务器上缓存数据。 这将允许所有用户共享该数据的单个实例,而不是在所有会话之间复制。 现在数据更轻了,您也许可以说服客户允许在会话中存储数据。

I can suggest a few more options

  1. Having the entire wizard as a single page with the tabs showing and hiding content via javascript on the client-side. This may cause the the initial page to load slower though.

  2. Caching the data at the server using the caching application block (or something similar). This will allow all the users to share a single instance of this data instead of duplicating across all sessions. Now that the data is lighter, you may be able to convince the customer to permit storing in the session.

迷你仙 2024-08-06 11:36:08

MVC 社区中存在很多反对使用 Session 的阻力。 问题是我们很多开发人员正在构建像银行网站这样的登录系统。 人们可能会争论隐藏字段,这在某些情况下有效,但当我们出于安全性和合规性需要让用户超时时,您有多种选择。 Cookie 并不可靠。 依赖 Javascript 计时器并不可靠,也不符合 508 标准,因为目标应该是优雅地降级。 因此对于登录来说,会话​​是一个不错的选择。 如果您将时间写入客户端浏览器、服务器数据库或服务器文件系统,您仍然需要管理每个用户的时间。

因此请谨慎使用会话,但不要害怕它们。 对于向导,​​从技术上讲,您可以序列化传递它们的隐藏字段。 我怀疑需求和范围将会变得更大,并且会话的授权/身份验证实现将是应用程序的关键。

There is a lot of resistance in the MVC community against using Sessions. Problems are that a lot of us developers are building login systems like a bank website. One could argue for hidden fields and that works for some situations but when we need to time a user out for security and compliance, then you have several options. Cookies are not reliable. Relying on Javascript timers are not reliable and are not 508 compliant as the goal should be to degrade gracefully. Thus for a Login, a Session is a good option. If you write the time to the client browser, to the server database or server file system, you still have to manage the time per user.

Thus use Sessions sparingly, but don't fear them. For the wizards, you technically can serialize hidden fields passing them around. I suspect the need and scope will become much greater and an authorization/authentication implementation with Sessions will be the crux of the application.

苏大泽ㄣ 2024-08-06 11:36:08

如果您无法使用ajax(用于验证和下拉菜单以及将向导转换为选项卡式页面的能力)并且无法使用html5(用于下拉缓存和本地存储中的表单状态保存),那么我认为您已经没有可用的“最佳实践”你必须求助于坏的(或更糟的)一种。

由于 MVC 在会话使用方面是 WebForms 的对手,也许您可​​以使用解决方法? 例如,除了将所有这些值存储在稍后需要清理的临时数据库记录中之外,您还可以设置 AppFabric 扩展 Windows Server 并用它来存储下拉列表项(范围可以适用于所有用户,因此如果更多用户同时使用系统,您只需要一次调用 Web 服务刷新缓存),以及在步骤之间临时存储对象。 您可以将 AppFabric 中的临时对象设置为自动过期,这样就无需进行清理。 如果您通过 Web 服务广泛调用另一个系统,它也有助于加快系统其他部分的速度。

If you cannot use ajax (for validation & dropdowns and ability to convert wizard to tabbed page) and cannot use html5 (for dropdown caching and form state saving in local storage), then I think you are pretty out of available "best practices" and you have to resort to bad (or worse) one.

As MVC is opponent of WebForms regarding session usage, maybe you can use a workaround? For example, besides storing all these values in some temporary database records you need to clean up later, you could set up AppFabric extension for Windows Server and use it to store dropdown list items (and scope can be for all users, so if more users are using system at the same time you need only one call to web service to refresh cache), and also to temporary store your objects between steps. You can set your temporary objects in AppFabric to automatically expire so cleanup is not necessary. It can also be of help for speeding up other parts of your system if you extensively call another system over web services.

此岸叶落 2024-08-06 11:36:08

我一直在处理同样的问题,虽然我的要求稍微简单一些(仅保留几个字符串的状态),但我的解决方案可能适合您。 我也有兴趣听听其他人对这种方法的想法。

我最终做的是:在控制器中,我只需将所需的数据转储到控制器的 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);  
    }
}

我喜欢这个的原因是我不必在我的视图页面上放置一堆隐藏参数。

I've been dealing with the same issue and, while my requirements are a little simpler (keeping state for just a few strings), my solution may work for you. I'd also be interested in hearing others thoughts on this approach.

What I ended up doing is: in the controller I just dump the data I want into the Session property of the Controller and then pull it out next time I need it. Something like this for your situation:

//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);  
    }
}

The thing I like about this is I don't have to put a bunch of hidden params around on my view pages.

在梵高的星空下 2024-08-06 11:36:08

答案可以在 Steve Sanderson 的 ASP.NET MVC 2/3,并且需要引用 MVC Futures 程序集。 此链接指向 Google书籍正是他所做的。

本质上,您将向导数据序列化到视图。 呈现隐藏字段,存储所有获取的信息。

您的控制器可以通过使用 OnActionExecutingOnResultExecuted(以满足重定向)来确定要执行的操作,并将其传递到下一个视图。

读一读——他解释得比我彻底得多。

The answer to this can be found in Steve Sanderson's ASP.NET MVC 2/3, and requires a reference to the MVC Futures assembly. This link to Google Books is exactly what he does.

In essence, you serialize the wizard data to the View. A hidden field is rendered storing all of the acquired information.

Your controller can work out what to do through the use of the OnActionExecuting and OnResultExecuted (to cater for redirects) to pass it to the next view.

Have a read - he explains it much more thoroughly than I can.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文