代码之家  ›  专栏  ›  技术社区  ›  Brian

我如何在MVC下创建一个简洁而宁静的向导?

  •  8
  • Brian  · 技术社区  · 15 年前

    我试图在构建应用程序时尽可能保持安静,但有一件事我从来都不确定,那就是如何创建一个向导类型的工作流程,保持安静和简洁。

    以多页注册流程为例。

    选项1: 我可以为每个步骤创建一个控制器,并在用户到达该步骤(或返回该步骤)时调用New或Edit。我以Step1_控制器、Step2_控制器等结束…

    选项2: 我可以创建一个单控制器,用一个参数、会话变量、状态机(无论什么)跟踪它们在注册过程中的位置。所以我要注册控制器/步骤?ID=1

    第一个选项是严格的rest,但不是非常简洁,以一些额外的控制器结束。第二种选择更为简洁,但打破了我愿意做的休息,但我并不轻视。

    有更好的选择吗?

    我在RubyonRails中工作,但这个问题适用于其他MVC实现,比如ASP.NET MVC。

    3 回复  |  直到 15 年前
        1
  •  7
  •   tvanfosson    15 年前

    实际上,我不太关心在一个一次性的巫师身上保持休息。我认为,对于可重复的操作,REST是最重要的——您希望URL基本上是可书签的,这样无论什么时候访问,您都能得到相同的数据视图。在一个多步骤向导中,您有一些依赖项无论如何都会破坏这个REST透视图。我的感觉是有一个单独的控制器,它可能有单独的动作,或者使用查询参数来指示您所处的步骤。这就是我如何构建激活向导(需要多个步骤)。

        2
  •  12
  •   eduncan911    15 年前

    如果您在这里应用一些DDD逻辑,这补充了MVC中的“M”,那么UI的状态(注册进度)属于应用程序层,它可以直接与域和基础结构层(四层:UI、应用程序、域和基础结构)对话。DDD的概念使您“思考”如何首先在代码中解决该解决方案。让我们跨过这一步…

    这是进度条

    您要在此处维护的状态是注册的步骤或进度。所以,我的第一步是记录进度或“步骤”。例如,步骤1:获取用户名/密码,步骤2:获取电子邮件。在本例中,我将应用逻辑将模型“移动”到下一步。最有可能是在注册服务(registrationservice.nextstep())上使用nextstep()方法。

    啊,但它属于应用层

    我将在应用程序层中创建一个名为注册服务的服务。我将在这里放置一个名为nextstep()的方法。但是请记住,域不会在这里保存模型的状态。在这种情况下,您需要将状态集中在应用程序层。因此,在本例中,nextstep()不会作用于模型对象(因为它不是域责任的一部分),而是作用于UI。所以,您需要一些东西来保持注册过程的状态。

    远离域模型,视图模型如何?

    所以现在我们知道我们必须在UI中保留某个东西的状态。MVC允许一个名为ViewModels的概念(在ASP.NET MVC中,不确定RoR将其称为什么)。视图模型表示将由视图和/或局部视图显示的模型。

    ViewModel将是保存此对象状态的最佳位置。让我们调用它,registrationProgressViewModel()并在它上面粘贴一个nextStep()方法。当然,这意味着应用程序层必须保留RegistrationProgressViewModel的位置,应用程序层将根据NextStep操作更改其内部。如果它很复杂,您可能希望在应用程序层中创建一个registrationProgressService(),并将nextStep()放在其中以抽象逻辑。

    如何传递视图模型?

    最后一部分是如何跟踪对象的状态。由于Web应用程序是无状态的,因此您必须通过其他方式保留控制权,然后再保留应用程序。在本例中,我将返回到以下任一种情况:1)将ViewModel序列化到客户机,并让客户机来回传递它;或者2)保留ViewModel的服务器端副本,并将某种类型的标识符来回传递给客户机。

    这是一个值得思考的好例子,因为我自己还没有完成这项工作。对于2,保存此视图模型状态的最安全和保险的方法是通过基础结构层将其持久化(是的,应用程序层可以直接与基础结构层对话)。对我来说,这似乎是一个很大的工作,因为有些事情可能会消亡,我的数据库中会有部分注册信息。

    但是,2会将用户的私人信息(用户名、密码、电子邮件、抄送等)全部保存在服务器端,而不会来回传递。

    最后,一个答案!

    因此,在经过它之后,我们想到了:

    • 在应用程序层中创建RegistrationProgressViewModel()。
    • 在应用程序层中使用NextStep(ViewModel VM)方法创建RegistrationProgressService()。
    • 执行nextstep()时,通过基础结构层将视图模型持久化到数据库中。

    这样,你就不必跟踪什么“步骤”?ID=2“,在视图或用户界面上,随着视图模型的更新和更新(经过身份验证、验证、持久化到数据库),继续前进。

    所以,您的下一个关注点是在UI中“前进”。使用1个控制器,使用步骤或命名步骤可以轻松完成此操作。

    我很抱歉,但我在写下面的C代码,因为这是我的语言。

    public class RegistrationController : Controller
    {
      // http://domain.com/register
      public ActionResult Index()
      {
        return View(new RegistrationProgressViewModel);
      }
    
      // http://domain.com/register
      // And this posts back to itself.  Note the setting 
      // of "CurrentStep" property on the model below.
      //
      public ActionResult Index(
          RegistrationProgressViewModel model)
      {
    
        // The logic in NextStep() here checks the
        // business rules around the ViewModel, verifies its
        // authenticity, if valid it increases the
        // ViewModel's "CurrentStep", and finally persists
        // the viewmodel to the DB through the Infrastructure
        // layer.
        //
        RegistrationProgressService.NextStep(model);
    
        switch (model.CurrentStep)
        {
          case 2:
            // wire up the View for Step2 here.
            ...
            return View(model);
          case 3:
            // wire up the View for Step3 here.
            ...
            return View(model);
          case 4:
            // wire up the View for Step4 here.
            ...
            return View(model);
          default:
            // return to first page
            ...
            return View(model);
        }
      }
    }
    

    您会注意到,这抽象了将模型内部状态验证到registrationprocessservice.nextstep()方法中的“业务逻辑”。

    锻炼身体。:)

    最后,您的“restful”URL是一个不错的和干净的post-to:/register,它需要填写一个具有特定属性的ViewModel。如果viewmodel无效,/register不会进入下一步。

        3
  •  1
  •   bastijn    15 年前

    虽然答案是非常好的选择,但我仍然使用以下给出的方法:

    Shoulders of Giants | A RESTful Wizard Using ASP.Net MVC .

    这绝对值得一看。尽管我必须说,这里给出的答案让我想在我有时间的时候重做这个巫师。