在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的属性值?
答案 0 :(得分:1)
验证不是控制器任务。您可以将所有必需的逻辑放在不同的模块中,并在那里传播请求。
答案 1 :(得分:0)
观看Jimmy Bogards Put your controller's on a diet演讲。如果你喜欢你所看到的,那么去购买他的书“MVC2 in Action”
这是关于如何分离您的疑虑的最佳演示,因此一切都不会落在控制器动作中。
答案 2 :(得分:0)
啊,但业务层 可以 影响模型状态。查看有关使用服务层验证的this tutorial。它也是存储库和控制反转的一个很好的介绍。
一般方法是为模型状态创建一个包装器,该包装器实现一个简单的接口,用于向模型状态添加错误。您的业务层对接口起作用 - 因此它与您的模型状态没有关系。您的单元测试可以实现一个假包装器,它也实现了相同的接口。
看起来您的具体示例是将用户的无效输入更改为有效输入。我的建议是简单地保留无效输入并使用AddModelError来反映控制器返回视图时的情况。