.NET MVC3中多页表单的最佳实践/设计

时间:2022-10-11 20:08:27

I am working on a web application that involves the user filling out a multi-step form that spans several pages. The form has tabbed navigation across the top (these links do not submit the current page) and a next button at the bottom (which does submit). I am considering several strategies for handling form submission/validation:

我正在开发一个Web应用程序,它涉及用户填写跨越多个页面的多步骤表单。表单顶部有标签导航(这些链接不提交当前页面)和底部的下一个按钮(确实提交)。我正在考虑处理表单提交/验证的几种策略:

  1. one action method and view per form page. When you hit next, it submits the form to the action method for the next page. If there are validation errors, you are redirected back to the previous page:

    每个表单页面一个操作方法和视图。当您点击下一步时,它会将表单提交给下一页的操作方法。如果存在验证错误,您将被重定向回上一页:

    • URL's are descriptive and can be copy-pasted
    • URL是描述性的,可以复制粘贴

    • Only redirects in the error case
    • 仅在错误情况下重定向

    • Since the redirect does not have the form data, we lose context about the submission which makes it hard to display certain error messages
    • 由于重定向没有表单数据,因此我们丢失了有关提交的上下文,这使得很难显示某些错误消息

    • The same validation logic works for redirecting the user if they try to visit a step in the flow that they aren't ready for yet
    • 如果用户尝试访问尚未准备好的流程中的步骤,则相同的验证逻辑可用于重定向用户

  2. one action method and view per form page. When you hit next, it submits the form to the current page action. If there are validation errors, the same view is returned. Otherwise, we redirect to the next page action:

    每个表单页面一个操作方法和视图。当您点击下一步时,它会将表单提交给当前页面操作。如果存在验证错误,则返回相同的视图。否则,我们会重定向到下一页操作:

    • URL's are descriptive and can be copy-pasted
    • URL是描述性的,可以复制粘贴

    • Redirects are very common (not sure if this is bad)
    • 重定向很常见(不确定这是不是很糟糕)

    • When displaying validation errors, we are in the same request as the form submission so we have full access to the invalid input
    • 显示验证错误时,我们与表单提交的请求相同,因此我们可以完全访问无效输入

    • Have to pass additional context if we want the ability to, for example, add a "Previous" button which also submits
    • 如果我们想要能够添加一个也提交的“上一个”按钮,则必须传递其他上下文

  3. one action method for ALL pages. URL's contain additional context about the step being submitted (e.g. MyController/MyAction/{step}). The controller message selects which view page to return depending on validation and the current step.

    所有页面的一种操作方法。 URL包含有关正在提交的步骤的其他上下文(例如MyController / MyAction / {step})。控制器消息根据验证和当前步骤选择要返回的视图页面。

    • URL's are not descriptive (e. g. if I submit step 1 to go to step 2, then the URL the user sees will be the same regardless of whether page 1 (invalid) or page 2 is returned
    • URL不是描述性的(例如,如果我提交步骤1转到步骤2,那么无论是否返回页面1(无效)或第2页,用户看到的URL都是相同的

    • No redirects
    • When displaying validation errors, we are in the same request as the form submission so we have full access to the invalid input
    • 显示验证错误时,我们与表单提交的请求相同,因此我们可以完全访问无效输入

  4. A different method I haven't listed here

    我没有在这里列出的另一种方法

I have tried to enumerate what I see as some of the pros and cons of each method, but I would be interested to know:

我试图列举我所看到的每种方法的一些优点和缺点,但我有兴趣知道:

  • What are other pros and cons of these methods? Are mine correct? Could some of the cons I've listed be designed around?
  • 这些方法的其他优点和缺点是什么?我的是正确的吗?我列出的一些缺点可以设计一下吗?

  • Is there a standard approach to this problem which I should be using? If so, why is it the standard approach?
  • 我应该使用这个问题的标准方法吗?如果是这样,为什么它是标准方法?

1 个解决方案

#1


2  

I would highly recommend option 2 with a minor modification. You may want to think about also creating one view model per action/view as well. If you have one model that spans all the pages, validation will occur across ALL properties, meaning that even though the user can only edit part of the model on each screen, they could get validation warnings for properties they can't see. We did this recently in a project and it worked beautifully. You have to do some data manipulation in the back-end to combine everything back together, but it was worth it in the end.

我强烈建议选项2稍作修改。您可能还想考虑为每个操作/视图创建一个视图模型。如果您有一个跨越所有页面的模型,则将在所有属性中进行验证,这意味着即使用户只能在每个屏幕上编辑模型的一部分,他们也可以获得他们看不到的属性的验证警告。我们最近在一个项目中做到了这一点并且工作得非常好。你必须在后端进行一些数据操作才能将所有内容重新组合在一起,但最终还是值得的。

As you said, your URLs would be deep-linkable, which means users can Copy/Paste, and more importantly, they can add the page as a favorite in their browser, allowing them to come back to the same place very easily. In my opinion this makes option 3 obsolete.

正如您所说,您的URL可以深层链接,这意味着用户可以复制/粘贴,更重要的是,他们可以将页面添加为浏览器中的收藏夹,从而可以非常轻松地返回到同一个位置。在我看来,这使选项3过时了。

You will also benefit from the fact that all of your logic for navigation is occurring in one place. You'll have to store the state of the "wizard" on the client (which page you're currently on) so that your controller knows what to do on submit. You'll want to analyze the state of the wizard and make a decision for where the user needs to go next. If you go with option 1, you won't know where you "came from" and server-validation errors will be difficult to display to the client. This is a beautiful example of the POST - REDIRECT - GET pattern. Each page would have 2 actions, a GET that takes simple ids, and a POST which takes more complex models. Post the server, figure out where to go next, redirect to a GET.

您还将受益于所有导航逻辑都在一个地方发生的事实。您必须在客户端(您当前所在的页面)上存储“向导”的状态,以便您的控制器知道如何处理提交。您需要分析向导的状态,并决定用户下一步需要做什么。如果选择选项1,则无法知道“来自哪里”,并且很难向客户端显示服务器验证错误。这是POST - REDIRECT - GET模式的一个很好的例子。每个页面都有2个动作,一个采用简单ID的GET,以及一个采用更复杂模型的POST。发布服务器,找出接下来的位置,重定向到GET。

Lastly, consider your previous button simply linking directly to the previous step, instead of submitting the form. Otherwise, the user could potentially get stuck on an invalid step. This happened to us and again, worked very nicely.

最后,考虑您之前的按钮只是直接链接到上一步,而不是提交表单。否则,用户可能会陷入无效步骤。这发生在我们身上,再一次,非常好地工作。

Hopefully this was helpful. Good luck!

希望这很有帮助。祝你好运!

#1


2  

I would highly recommend option 2 with a minor modification. You may want to think about also creating one view model per action/view as well. If you have one model that spans all the pages, validation will occur across ALL properties, meaning that even though the user can only edit part of the model on each screen, they could get validation warnings for properties they can't see. We did this recently in a project and it worked beautifully. You have to do some data manipulation in the back-end to combine everything back together, but it was worth it in the end.

我强烈建议选项2稍作修改。您可能还想考虑为每个操作/视图创建一个视图模型。如果您有一个跨越所有页面的模型,则将在所有属性中进行验证,这意味着即使用户只能在每个屏幕上编辑模型的一部分,他们也可以获得他们看不到的属性的验证警告。我们最近在一个项目中做到了这一点并且工作得非常好。你必须在后端进行一些数据操作才能将所有内容重新组合在一起,但最终还是值得的。

As you said, your URLs would be deep-linkable, which means users can Copy/Paste, and more importantly, they can add the page as a favorite in their browser, allowing them to come back to the same place very easily. In my opinion this makes option 3 obsolete.

正如您所说,您的URL可以深层链接,这意味着用户可以复制/粘贴,更重要的是,他们可以将页面添加为浏览器中的收藏夹,从而可以非常轻松地返回到同一个位置。在我看来,这使选项3过时了。

You will also benefit from the fact that all of your logic for navigation is occurring in one place. You'll have to store the state of the "wizard" on the client (which page you're currently on) so that your controller knows what to do on submit. You'll want to analyze the state of the wizard and make a decision for where the user needs to go next. If you go with option 1, you won't know where you "came from" and server-validation errors will be difficult to display to the client. This is a beautiful example of the POST - REDIRECT - GET pattern. Each page would have 2 actions, a GET that takes simple ids, and a POST which takes more complex models. Post the server, figure out where to go next, redirect to a GET.

您还将受益于所有导航逻辑都在一个地方发生的事实。您必须在客户端(您当前所在的页面)上存储“向导”的状态,以便您的控制器知道如何处理提交。您需要分析向导的状态,并决定用户下一步需要做什么。如果选择选项1,则无法知道“来自哪里”,并且很难向客户端显示服务器验证错误。这是POST - REDIRECT - GET模式的一个很好的例子。每个页面都有2个动作,一个采用简单ID的GET,以及一个采用更复杂模型的POST。发布服务器,找出接下来的位置,重定向到GET。

Lastly, consider your previous button simply linking directly to the previous step, instead of submitting the form. Otherwise, the user could potentially get stuck on an invalid step. This happened to us and again, worked very nicely.

最后,考虑您之前的按钮只是直接链接到上一步,而不是提交表单。否则,用户可能会陷入无效步骤。这发生在我们身上,再一次,非常好地工作。

Hopefully this was helpful. Good luck!

希望这很有帮助。祝你好运!