Asp.net mvc 从自定义模型绑定器点击数据库可以吗?

Asp.net mvc 从自定义模型绑定器点击数据库可以吗?,asp.net-mvc,modelbinders,Asp.net Mvc,Modelbinders,假设我有一个对象,它从HttpPost获取一些数据,从数据库获取一些数据。我想我应该允许ModelBinder进入数据库/存储库,查找文章中丢失的数据。实际上,这是个好主意还是个坏主意 我会说,不 原因如下:它将创建对数据库的依赖性,用于测试控制器操作,这不容易抽象出来。我认为这是个坏主意。模型绑定器的思想是,它从请求中获取参数,并根据这些参数创建模型。如果您的模型绑定器在幕后填充了数据库中的一些细节,这就打破了这种模式。我更愿意通过直接从数据库显式获取所需的额外数据来公开控制器中的数据库调用。

假设我有一个对象,它从HttpPost获取一些数据,从数据库获取一些数据。我想我应该允许ModelBinder进入数据库/存储库,查找文章中丢失的数据。实际上,这是个好主意还是个坏主意

我会说,不


原因如下:它将创建对数据库的依赖性,用于测试控制器操作,这不容易抽象出来。

我认为这是个坏主意。模型绑定器的思想是,它从请求中获取参数,并根据这些参数创建模型。如果您的模型绑定器在幕后填充了数据库中的一些细节,这就打破了这种模式。我更愿意通过直接从数据库显式获取所需的额外数据来公开控制器中的数据库调用。请注意,如果经常使用,可以将其重构为一种方法。

我认为这非常好,并且一直使用这种技术

唯一反对的论点是非常迂腐的,相当于对哲学的争论。IMHO您可以将“填充缺少的发布数据”代码作为基本控制器中的方法与ActionFilter中的方法与ModelBinder中的方法放入MVC应用程序中。这完全取决于谁承担什么责任。对我来说,模型绑定器可以做的不仅仅是从发布的值连接一些属性

我喜欢在modelbinder中进行数据库调用的原因是它有助于清理操作方法

    //logic not in modelbinder
    public ActionResult Edit( KittyCat cat )
    {
        DoSomeOrthagonalDatabaseCall( cat );

        return View( new MODEL() );
    }
vs


它违反了MVC的工作方式。ModelBinder用于从来自视图的数据中绑定模型。填充数据库中缺少的信息应该由控制器处理。理想情况下,它将具有用于执行此操作的相同数据层/存储库类

它应该在控制器中的原因是因为此代码是业务逻辑。业务规则规定某些数据可能丢失,因此必须由操作的大脑,即控制器来处理

更进一步说,假设您想登录数据库,了解用户没有发布的信息,或者在获取丢失的数据和有关数据的电子邮件管理员时捕获异常。您必须以这种方式将这些内容放入模型绑定器中,随着模型绑定器越来越偏离其原始用途,它变得越来越难看


基本上,除了控制器之外,你希望所有的事情都尽可能地愚蠢和专业化,只知道如何执行其专门领域的专业知识,这纯粹是为了帮助控制器。

鉴于我对这些类型的事情的思考自2010年初以来一直在发展,我决定编辑我的原始答案

在我最初的回答中,我基本上表达了这样的观点,虽然我的直觉告诉我你不应该这样做,但我很不舒服地说,我们不应该这样做,但我无法清楚地说出原因


现在,我建议不要这样做,因为模型绑定器的职责是将用户请求转换为请求模型,并且从请求中获取的数据超出了这一职责范围。

我认为这是可以的。创建对数据库的依赖关系的参数是错误参数,原因有二:

1-数据库访问应该通过存储库接口进行抽象。存储库接口是域模型的一部分,它们的实现是基础设施/数据访问层的一部分。因此,对数据库没有依赖关系

2-模型绑定器和控制器都是使用ASP.NETMVC框架实现的表示层的一部分。若允许控制器使用存储库接口访问数据库,为什么不允许使用模型绑定

此外,在某些情况下,您最好从模型绑定器中填充模型中缺少的数据。考虑一下在视图中有下拉列表的场景。第一次加载视图时,将填充下拉列表。用户提交表单,但验证失败。所以您需要再次返回表单。在此阶段,您必须在模型中为下拉列表重新填充列表。在控制器中执行此操作看起来很难看:

public ActionResult Save(DocumentViewModel viewModel)
{
     if (!ModelState.IsValid)
     {
         viewModel.Categories = _repository.GetAll();
         return View(viewModel);
     }
}

我相信这里的类别初始化是丑陋的,就像一种代码味道。若您有一些属性需要从数据库中填写,该怎么办?如果您有多个操作以DocumentViewModel作为参数,该怎么办?你得一次又一次地重复这丑陋的一步。更好的方法是使用模型绑定器填充模型的所有属性,并将其传递给控制器。因此,传递给控制器的对象处于“一致”状态

如何,通常我给动作一个完全填充的模型作为参数,在单元测试中完全跳过模型绑定器?为什么测试中的代码应该关心模型是如何构建的?如果您的模型是从HttpPost绑定的,有些是从数据库绑定的,那么它将绑定到controller/repository/model binder中,那么,使用模型绑定器不是一种避免添加和编辑操作可能需要的重复功能的干净方法吗?关于:“它将创建对数据库的依赖,用于测试控制器操作,这不容易抽象出来。”这是错误的。您可以轻松访问modelbinder中控制器内部的任何内容,而不需要创建其他依赖项。因此,如果您将DAL/存储库/服务注入到控制器中,您也可以在Modelbinder中获得它。这就是避免将ModelBinder与db access混合使用的充分理由。@Byron如果您必须进行一些数据库访问以将参数填充到单元测试的操作方法中,那么宇宙中出现了一些错误:)您只需调用_controller.SomeAction(新实体{Param1=1,Param2=2,Param 3=3});。那个
public ActionResult Save(DocumentViewModel viewModel)
{
     if (!ModelState.IsValid)
     {
         viewModel.Categories = _repository.GetAll();
         return View(viewModel);
     }
}