如何避免在控制器中放置域逻辑?

时间:2010-09-20 04:21:14

标签: c# asp.net-mvc

在PRO ASP.NET MVC上:

  

当然可以放置域名   逻辑到控制器,即使   你不应该,因为它似乎   在一些压力的时刻权宜之计。

只是一个人为的例子,如果应用程序不允许否定订单,那么将数量的变化放在哪里?如果我们遵循域逻辑不应该放在控制器中的原则,那么使用它肯定是不可取的:

[AcceptVerbs(HttpVerbs.Post)]        
public ActionResult PlaceOrder(Order order)
{
 if (ModelState.IsValid)
 {
  order.Submit();
  return View("Thanks", order);
 }
 else
 {
    if (order.Quantity <= 0)
    {
        ModelState.Remove("Quantity");
        order.Quantity = 1;  
    }
    return View(order);
 }
}

因此,以下代码是遵循MVC原则的正确代码,即它遵循关注点分离,如果它是域逻辑,则不应在控制器中看到其代码。所以这就是我尝试在域模型中放置域逻辑的方法:

public class Order : IDataErrorInfo
{
 public int OrderId { set; get; }
 public int ProductId { set; get; }
 public int Quantity { set; get; }

 public string Error { get { return null; } }

 public string this[string propName]
 {
  get
  {
   if (propName == "Quantity" && Quantity <= 0)
   {
    Quantity = 1;
    return "0 or negative quantity not allowed, changed it to 1";
   }
   else
    return null;

  }
 }
}

Controller(没有域逻辑):

[AcceptVerbs(HttpVerbs.Post)]        
public ActionResult PlaceOrder(Order order)
{
 if (ModelState.IsValid)
 {
  order.Submit();
  return View("Thanks", order);
 }
 else
 {
  // Response.Write(order.Quantity.ToString()); // this was changed in Model
  return View(order); // but the View didn't reflect that fact
 }
}

该方法的唯一问题是,Model(Order)不能影响ModelState,因此,程序始终显示用户最后输入的内容。

什么是最好的方法,所以我仍然可以避免将域逻辑放在控制器中,而View仍然可以反映Model的属性值?

3 个答案:

答案 0 :(得分:1)

验证不是控制器任务。您可以将所有必需的逻辑放在不同的模块中,并在那里传播请求。

答案 1 :(得分:0)

观看Jimmy Bogards Put your controller's on a diet演讲。如果你喜欢你所看到的,那么去购买他的书“MVC2 in Action

这是关于如何分离您的疑虑的最佳演示,因此一切都不会落在控制器动作中。

答案 2 :(得分:0)

啊,但业务层 可以 影响模型状态。查看有关使用服务层验证的this tutorial。它也是存储库和控制反转的一个很好的介绍。

一般方法是为模型状态创建一个包装器,该包装器实现一个简单的接口,用于向模型状态添加错误。您的业​​务层对接口起作用 - 因此它与您的模型状态没有关系。您的单元测试可以实现一个假包装器,它也实现了相同的接口。

看起来您的具体示例是将用户的无效输入更改为有效输入。我的建议是简单地保留无效输入并使用AddModelError来反映控制器返回视图时的情况。