7

在计算机科学中,我们被教导说每种方法都应该做一件事,而且只做一件事。我有点困惑,我们看到像下面这样的 MVC 操作作为良好实践的例子

    [AcceptVerbs(HttpVerbs.Post), Authorize]
    public ActionResult Edit(int id, FormCollection collection) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (!dinner.IsHostedBy(User.Identity.Name))
            return View("InvalidOwner");

        try {
            UpdateModel(dinner);

            dinnerRepository.Save();

            return RedirectToAction("Details", new { id=dinner.DinnerID });
        }
        catch {
            ModelState.AddModelErrors(dinner.GetRuleViolations());

            return View(new DinnerFormViewModel(dinner));
        }
    }

基本上这段代码提供了很多功能:

  1. 定义如何访问操作 - 仅发布
  2. 定义谁可以访问操作 - 授权
  3. 访问持久化机制 -dinnerRepository
  4. 访问状态信息 - (User.Identity.Name)
  5. 将 NameValueCollection 转换为强类型对象 - UpdateModel()
  6. 为每个指定 3 个可能的 ActionResult 和内容 - InvalidOwner/Details/Edit 视图

对我来说,这似乎是一种方法的太多责任。这也是一个相当简单的操作,即它不处理常见场景,例如:

  1. 检查业务规则 - “永远不要相信用户输入”
  2. 导航路径 - 成功保存后始终返回“详细信息”
  3. 不同的返回类型 - 有人想从网格中调用“编辑”并需要 JsonResult?
  4. 更好的错误处理 - 如果在 GetDinner(id) 期间无法访问数据库,则 YSOD
  5. 构建额外的视图数据 - 下拉列表的 SelectLists

更不用说围绕这个单一方法所需的测试量,即模拟/伪造 FormCollection/UserIdentity/Authorization Provider/Repository/等。

我的问题是我们如何避免在控制器动作中塞进这么多东西?

我倾向于认为“意见”是一个很好的概念,尤其是“雷电原则”。虽然我非常尊重参与构建FubuMVC的人及其背后的原因,但我需要一些我现在可以使用的东西。

编辑-好吧,看来我是在追求这样的东西-自以为是的控制器。我需要进一步检查它,因为它适用于 MVC Preview 5,所以我可能需要自己更新它。

4

4 回答 4

3

对我来说,这个方法只做一件事:用从 web 表单接收到的编辑值更新模型。

很明显,这样做需要发生一些事情,但它们是原子的并且定义明确。如果您需要修改模型的这部分需要如何更新,这是要查找和更新的控制器操作。

您可能会争辩说,由于此处检查了业务规则,因此不符合 Thunderdome 原则之一“控制器应该是轻量级的”。但是 NerdDinner 是一个非常琐碎的应用程序,将它放在额外的层中是没有意义的。

如果你发现这个方法做的太多了,也许你应该找到一种禁止在一个方法中放置多个语句的语言。

于 2009-06-10T13:51:51.390 回答
1

我对你的帖子有点困惑。首先你抱怨这个动作做得太多,然后你抱怨没有做得更多。

编辑添加:

老实说,这不是一个非常复杂的控制器动作。这是否是一个最佳实践示例是有争议的,但是,您可能不会比这更简单。我想你可以将其中的一些分解成单独的例程,但在某些时候你必须决定在哪里画这条线。最终,我们作为程序员必须编写软件。设计原则很棒,但如果我们对它们太死板,什么都不会建成。

于 2009-06-10T13:46:52.710 回答
0

我认为它仍在执行所需的最低限度的行动……因为这个“行动”可能不适合绝对单一的责任——但它是单一的行动

  1. 属性告诉 ASP.NET,此方法仅适用于 HTTP.Post,并且尝试使用它的身份必须经过授权。- 良好的安全性。所以在这一点上,实际上没有做任何事情。这些只是告诉服务器要检查什么。

    即如果不是 HTTP.post方法将不起作用,如果您不是列表,则不会起作用

  2. 有验证来检查用户身份是否与晚餐的身份匹配。- 完整性检查。

  3. 这是基于强类型检查 - 执行 UpdateModel(dinner) - 只是确保模型中的当前对象已使用新数据更新,然后调用存储库到 Save()。- 这仍然是一个动作单元 - 更新模型以便我们可以调用保存和持久化。

  4. 验证检查在 Catch 中处理,该 Catch 将 RuleViolations 添加到模型中,并将用户返回到有问题的视图 - 即编辑/创建部分视图,该视图将责任传递给要处理的视图。

  5. 如果保存工作 - 它只是将用户的“工作流程”移动到细节 - 即从内存中清除表单并将工作移回细节。恕我直言,很棒-我们处于 POST 场景中,并且内存中没有东西-很好。

  6. 不将流程移回细节并留在部分编辑视图上会更容易。

于 2009-06-10T14:04:24.733 回答
-1

我对“单一责任原则”的问题是人们并不总是对事件进行相同的细分——有些比其他的更细化。所以看起来,一个人可以很容易地找到一个动作的更细化的视图,但最微不足道的情况。

于 2012-01-14T20:07:07.637 回答