Asp.Net MVC行动 - 关注点分离/单一责任原则

时间:2009-06-10 13:41:00

标签: asp.net-mvc separation-of-concerns

在计算机科学中,我们被教导每种方法应该只做一件事,一件事。我有点困惑,然后我们看到MVC操作,如下面的given as examples of good practice

    [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个可能的ActionResults和内容 - InvalidOwner / Details / Edit views
  7. 对我而言,这似乎对一种方法的责任太多了。它也是一个相当简单的动作,即它不处理常见的情况,如:

    1. 检查业务规则 - “绝不信任用户输入”
    2. 导航路径 - 成功保存后,始终返回“详细信息”
    3. 不同的返回类型 - 有人想从网格中调用“编辑”并需要JsonResult吗?
    4. 更好的错误处理 - 如果在GetDinner(id)期间无法访问数据库,则为YSOD
    5. 构建其他视图数据 - 下拉列表的选择列表
    6. 不要太提及围绕这种方法所需的测试量,即FormCollection / UserIdentity / Authorization Provider / Repository / etc的模拟/伪造。

      我的问题是我们如何避免在控制器操作中塞入如此多的东西?

      我倾向于认为"opinions"是一个伟大的概念,尤其是“Thunderdome Principle”。虽然我非常尊重参与构建FubuMVC的人及其背后的原因,但我需要现在可以使用的东西。

      编辑 - 好吧,我似乎是在追求这样的事情 - Opinionated Controller。我需要进一步检查它,因为它适用于MVC Preview 5,所以我可能需要自己更新。

4 个答案:

答案 0 :(得分:3)

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

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

你可以争辩说,由于这里检查了业务规则,因此无法满足Thunderdome原则中的一个“控制器应该很轻”。但NerdDinner是一个非常简单的应用程序,将它放在一个额外的层中是没有意义的。

如果您发现此方法做得太多,或许您应该找到一种禁止在方法中放置多个语句的语言。

答案 1 :(得分:1)

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

编辑添加:

老实说,这不是一个非常复杂的控制器动作。它是否是一个最佳实践的例子是有争议的,但是,你可能不会比这简单得多。我想你可以把它们分解成单独的例程,但是在某些时候你必须决定在哪里绘制那条线。最终,我们作为程序员必须编写软件。设计原则很棒,但是如果我们对它们过于刻板,那么任何东西都无法构建。

答案 2 :(得分:0)

我认为它仍在进行所需的最小操作。对于此“操作”可能不符合绝对单一责任 - 但它是单一操作

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

    即如果不是HTTP.post 方法将不起作用,如果您不是列表,将无法正常工作

  2. 验证用户身份是否与晚餐相匹配。 - 理智检查。

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

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

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

  6. 将流程移回到详细信息并离开部分编辑视图会更容易。

答案 3 :(得分:-1)

我对“单一责任原则”的问题是,人们并不总是将事件分段相同 - 有些比其他事件更精细。所以看起来,人们可以很容易地找到一个更细粒度的行动视图,但最简单的案例。