将 DTO 转换为视图模型的位置



我继承了一个MVC2项目,使用了一个非常标准且保存良好的DDD模式。 我也一直在阅读整个DTO/ViewModel辩论。

目前,我们的DTO经常像ViewModels一样使用。 老实说,这对我们正在做的事情没有影响,但我想在升级网站时使用适当的 ViewModels。

这是我的问题:

我们的"域"项目的模型当前保存实体并将 DTO 返回给我的控制器。 现在我需要将该 DTO 映射到视图模型。 我应该在哪里执行此操作?

  • 就在控制器中?
  • 在域项目中?
  • 别处?

我将我的视图模型与"Web"项目中的视图放在一起,因此在域项目中转换DTO -> ViewModel感觉错误。 在控制器中执行此操作也感觉不对。

其他人做了什么?

编辑:

此问题/答案建议在控制器中处理它。 这当然很容易过度思考。

DTO通常是特定于技术的。例如,在 .NET 世界中,DTO 可能使用DataContractDataMember序列化属性进行修饰。此外,DTO 与返回它们的服务一起在六边形体系结构方面形成域的适配器。它们使您的域适应特定的传输技术,例如HTTP,因此它们位于您的域之外。换句话说,域不应了解 DTO,而 DTO 应在单独的项目中定义。包含服务的项目应具有将域对象映射到 DTO 的映射代码。

ASP.NET MVC 项目本质上是相似的 - 它使您的服务/DTO(或域对象直接)适应表示技术,特别是 HTML。因此,DTO不应该知道ViewModels。相反,MVC 控制器应调用 DTO 和 ViewModel 之间的映射。这可以通过多种方式完成,但我发现最有效的是 ViewModel 中的构造函数接受 DTO。此外,如果控制器操作需要创建要发送回服务的 DTO,则 ViewModel 可以包含基于 ViewModel 创建 DTO 的方法。它包含 ViewModel 中最接近实际数据的所有映射代码 - 信息专家模式的实例。实现这一点的另一种方法是使用类似AutoMapper的东西,它使用基于约定的映射来避免样板代码。除此之外的任何事情,除非有需要,否则我会认为矫枉过正。

在许多情况下,您的 ViewModel 最终看起来就像 DTO 一样,但具有 ASP.NET MVC 特定的属性用于绑定和验证。尽管这似乎违反了 DRY,但这些实际上是单独的责任。

首先,始终为您的视图使用显式视图模型,不要将 DTO 一直传递到视图。这是更前期的工作,但它使您可以更好地控制视图中所需的确切数据(它还可以防止像 EF 这样的框架旁加载您可能使用或可能不会使用的大量额外数据)

其次,本文概述了 Orchestrator 模式 http://www.simple-talk.com/dotnet/asp.net/never-mind-the-controller,-here-is-the-orchestrator/它可能只是其他模式的另一个名称,但我喜欢这种格式。

实质上,您需要为每个控制器创建一个业务流程协调程序。业务流程协调程序接收数据(通常是 ViewModel,以及所需的任何其他基本数据类型,特别是来自 HttpContext 的数据类型),并返回 ViewModel(如果视图需要,否则返回其他返回类型)。

这种格式的好处是,你可以轻松地对实际逻辑进行单元测试,而不必尝试模拟控制器需要的 HttpContext 内容。

听起来像是你想在专门构建的映射类/模块中做的事情。

我个人会让我的控制器依赖于映射服务,然后在使用新映射的视图模型返回视图之前将实际转换委托给该服务。

public class DemoController : Controller
{
    private readonly IMappingService _mappingService;
    public DemoController(IMappingService mappingService)
    {
        _mappingService = mappingService;
    }
    public ActionResult Stuff()
    {
        var vm = _mappingService.Map(yourDto);
        return View(vm);
    }
}

一个不错的方法是使用第二个构造函数重载 ViewModel 上的构造函数,该构造函数将 dto 作为参数。这意味着您可以在视图模型本身中处理映射。这使您的控制器保持美观整洁,而无需设置映射服务。

最新更新