Asp.Net MVC 操作 - 关注点分离/单一职责原则

发布于 2024-07-24 17:33:25 字数 1974 浏览 6 评论 0原文

在计算机科学中,我们被教导每种方法应该只做一件事。 我有点困惑,我们看到像下面这样的 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. 定义如何访问 Action - Post only
  2. 定义谁可以访问 Action - 授权
  3. 访问持久性机制 -dinnerRepository
  4. 访问状态信息 - (User.Identity.Name)
  5. 将 NameValueCollection 转换为强类型对象 - UpdateModel ()
  6. 为每个指定 3 个可能的 ActionResults 和内容 - InvalidOwner/Details/Edit 视图

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

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

不太提及围绕此单一方法所需的测试量,即对 FormCollection/UserIdentity/Authorization Provider/ 进行模拟/伪造存储库/等。

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

我倾向于认为"意见" 是一个很棒的概念,尤其是“Thunderdome 原则”。 虽然我非常尊重参与构建 FubuMVC 的人以及他们这样做背后的原因,但我需要一些我能做到的东西立即使用。

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

In computer science we've been taught that each method should do one thing and one thing only. I'm a little confused then that we see MVC actions like the following 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));
        }
    }

Basically this piece of code provides a lot of functionality:

  1. Defines how to access the Action - Post only
  2. Defines who can access the Action - Authorize
  3. Accesses persistence mechanism - dinnerRepository
  4. Accesses state information - (User.Identity.Name)
  5. Converts NameValueCollection to strongly typed object - UpdateModel()
  6. Specifies 3 possible ActionResults and content for each - InvalidOwner/Details/Edit views

To me this seems like too many responsibilities for one method. It is also a fairly simple action ie it doesn't deal with common scenarios like:

  1. Checking business rules - "Never trust user input"
  2. Navigation paths - On successful save always returns to "Details"
  3. Different return types - Someone wants to call "Edit" from a grid and needs a JsonResult?
  4. Better error handling - YSOD if the database is not accessible during GetDinner(id)
  5. Constructing additional view data - SelectLists for Drop down lists

Not too mention the amount of testing required around this single method i.e. mocking/faking for FormCollection/UserIdentity/Authorization Provider/Repository/etc.

My question is how do we avoid cramming so much stuff into our controller actions?

I tend to think "opinions" are a great concept, especially the "Thunderdome Principle". While I have great respect for the guys involved with building FubuMVC and their reasons behind doing so, I need something I can use right now.

Edit - Well it seems I was after something like this - Opinionated Controller. I'll need to examine it further as it's for MVC Preview 5 so i may need to update it myself.

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

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

发布评论

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

评论(4

入画浅相思 2024-07-31 17:33:26

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

显然,要做到这一点需要发生一些事情,但它们是原子的并且定义良好。 如果您需要修改模型的这部分需要更新的方式,这是要查找和更新的控制器操作。

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

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

To me, this method does only one thing: update the model with the edited values received from the web form.

It's clear that doing this requires a couple of things to happen, but they are atomic and well defined. If you ever need to modify how this part of the model needs to be updated, this is the controller action to look for and update.

You could argue that one of the Thunderdome principles, "controllers should be light", is not met since a business rule is checked here. But NerdDinner is a very trivial app that it makes no sense to place this in an extra layer.

If you find that this method does too much, perhaps you should find a language in which it's forbidden to place more than one statement in a method.

夜深人未静 2024-07-31 17:33:26

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

编辑添加:

老实说,这不是一个非常复杂的控制器操作。 这是否是最佳实践示例是有争议的,但是,您可能不会得到比这更简单的结果。 我想你可以将其中一些分解成单独的例程,但在某些时候你必须决定在哪里划清界限。 最终,我们作为程序员必须编写软件。 设计原则很棒,但如果我们对它们过于严格,那么什么也建不起来。

I am a little confused by your post. First you complain that this action is doing to much, and then you complain that is not doing more.

Edited to add:

Honestly this is not a very complicated controller action. Whether it is a best practice example or not is debatable, but, you probably are not going to get a whole lot simpler than that. I suppose you could break some of it up into separate routines, but at some point you have to decide where to draw that line. Ultimately we, as programmers have to write software. Design principals are awesome, but if we are too rigid with them nothing will ever get built.

计㈡愣 2024-07-31 17:33:26

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

  1. 属性向 ASP.NET 表明此方法仅适用于 HTTP.Post,并且尝试使用该方法的身份必须经过授权。 - 良好的安全性。 所以此时实际上什么也没做。 这些只是告诉服务器要检查什么。

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

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

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

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

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

  6. 不移动流程来支持详细信息,而只保留部分编辑视图会更容易。

I think it is still doing on the minimum actions required..for this "Action" may not fit the Absolute single responsbility - but it is single action

  1. The the attributes are saying to ASP.NET that this method will only work with HTTP.Post, and identity that is trying to use it must be authorised. - Good Security. So at this point nothing is actually being done. These are just telling the server what to check.

    ie if not HTTP.post method will not work, and if your not the list, wont work.

  2. There is validation to check if the user Identity matchs those of the dinner. - Sanity Check.

  3. This is based on Strong Type Checking - do UpdateModel(dinner) - is just making sure that the current objects in the model have been updated with the new data, then the repository is called to Save(). - This is still in the one unit of action - updating the model so that we can call save and persist.

  4. Validation checks are handled in the Catch which is adding RuleViolations to the Model, and returning the user back to the offending view - ie edit/create partial view which is passing responisbility to that to deal with.

  5. If the save works - its is just moving the "workflow" of the user to the Details - i.e clearing the form from memory and moving the work back to the details. IMHO great as - we are in a POST scenario and stuff not lying around in memory - Good.

  6. It would be easier not to move the flow to back the details and just leave on the partial edit view.

怪我太投入 2024-07-31 17:33:26

我对“单一责任原则”的看法是,人们并不总是对事件进行相同的划分——有些事件比其他事件更细粒度。 因此,人们似乎可以轻松地在所有情况下(但最微不足道的情况下)找到对某一行为的更细致的看法。

the issue that i have with the "single responsibility principle" is that people do not always segment events the same - some more granular than others. so it would seem, that one could easily find a more granular view of an action in all, but the most trivial cases.

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