假设我有一个从 HttpPost 和数据库中获取一些数据的对象。我想我想让 ModelBinder 进入数据库/存储库以获取帖子中丢失的数据。在实践中,这是一个好主意还是坏主意?
6 回答
鉴于我对这类事情的想法自 2010 年初以来已经发展,我决定编辑我的原始答案。
在我最初的回答中,我基本上表达了,虽然我的直觉告诉我你不应该这样做,但我很不自在地说我们不应该在无法阐明原因的情况下这样做。
现在,我建议不要这样做,因为模型绑定器的职责是将用户请求转换为请求模型,并且检索可以从请求派生的数据之外的数据超出了此职责范围。
我会说一个坏主意。模型绑定器的想法是它从请求中获取参数并从中创建模型。如果您的模型绑定器在幕后填充了数据库中的一些细节,这将打破范式。我宁愿通过直接从数据库中显式获取所需的额外数据来公开我的控制器中的数据库调用。请注意,如果经常使用,可以将其重构为方法。
我认为这非常好,并且一直使用这种技术。
唯一反对的论点是非常迂腐的,相当于争论哲学。恕我直言,您可以将“填写丢失的已发布数据”代码作为基本控制器中的方法与 ActionFilter 中的方法与 ModelBinder 中的方法一起放入 MVC 应用程序中。这完全取决于谁承担什么责任。对我来说,模型绑定器可以做的不仅仅是从发布的值中连接一些属性。
我喜欢在我的模型绑定器中进行数据库调用的原因是因为它有助于清理你的操作方法。
//logic not in modelbinder
public ActionResult Edit( KittyCat cat )
{
DoSomeOrthagonalDatabaseCall( cat );
return View( new MODEL() );
}
对比
//logic in model binder
public ActionResult Add( KittyCat cat )
{
return View( new MODEL() );
}
它违反了 MVC 的工作方式。ModelBinder 用于从来自视图的数据中绑定模型。从数据库中填充缺失的信息应该由控制器处理。理想情况下,它将具有用于执行此操作的相同数据层/存储库类。
它应该在控制器中的原因是因为这段代码是业务逻辑。业务规则规定某些数据可能会丢失,因此必须由操作的大脑、控制器来处理。
更进一步,假设您想登录数据库用户未发布的信息,或者在获取丢失的数据和电子邮件管理员时捕获异常。您必须以这种方式将它们放入模型绑定器中,并且随着模型绑定器变得越来越偏离其原始用途,它变得越来越丑陋。
基本上,您希望除了控制器之外的所有东西都尽可能地愚蠢和专业,只知道如何执行其特定的专业领域,这纯粹是为了协助控制器。
我会说,不。
原因如下:它会在您的数据库上创建一个依赖项,以测试您的控制器操作,这些操作不容易抽象出来。
我会说没关系。创建对数据库的依赖的论点是一个错误的论点,原因有两个:
1- 数据库访问应该通过存储库接口进行抽象。存储库接口是域模型的一部分,它们的实现是基础设施/数据访问层的一部分。所以对数据库没有依赖性。
2- 模型绑定器和控制器都是使用 ASP.NET MVC 框架实现的表示层的一部分。如果允许控制器使用存储库接口访问数据库,为什么不允许模型绑定器?
此外,在某些情况下,您会“更好地”从模型绑定器中填充模型中缺失的数据。考虑在视图中有一个下拉列表的场景。第一次加载视图时,会填充下拉列表。用户提交表单但验证失败。因此,您需要再次返回表单。在这个阶段,您必须在下拉列表的模型中重新填充列表。在 Controller 中执行此操作看起来很难看:
public ActionResult Save(DocumentViewModel viewModel)
{
if (!ModelState.IsValid)
{
viewModel.Categories = _repository.GetAll();
return View(viewModel);
}
}
我相信这里的类别初始化是丑陋的,就像代码的味道。如果您有一些需要从数据库中填写的属性怎么办?如果您有多个以 DocumentViewModel 作为参数的操作怎么办?你必须一遍又一遍地重复这个丑陋的步骤。更好的方法是使用 Model Binder 填充模型的所有属性并将其传递给 Controller。因此传递给控制器的对象处于“一致”状态。