【问题标题】:Can we use only DTO instead of ViewModel? [closed]我们可以只使用 DTO 而不是 ViewModel 吗? [关闭]
【发布时间】:2018-05-29 05:30:35
【问题描述】:

我们目前使用 DTO 进行 Web API 请求和响应

并使用 ViewModel 将数据传递给 MVC 中的 View

目前,我们有:

  1. DTO 作为一个单独的项目
  2. ViewModel 位于 UI 项目中(与 Controllers 一起的另一个文件夹)

在我们的案例中,我看到的唯一区别是 DTO 必须通过网络传递并作为 JSON 发送,而 ViewModel 必须在视图内部传递才能呈现为 HTML。

我们应该为 MVC 应用程序和我们的应用程序/其他客户端维护单独的传输对象,还是只通过 DTO 完成这两项工作,即在 View 内部传递 DTO 而不是 ViewModel?它有什么可能的缺点?

我阅读了许多回复 here,但在我们的案例中没有示例和令人信服的理由将 ViewModel 和 DTO 分开。

【问题讨论】:

  • MVC 在技术上不需要 ViewModel。它只需要一个模型(只有一个 M)。一个模型可以在多个视图中使用。你是在问一个模型在哲学意义上是否像一个 DTO?或者您是在问是否要求每个 View 都有自己的 ViewModel(答案是否定的)?

标签: c# asp.net-mvc viewmodel dto asp.net-mvc-viewmodel


【解决方案1】:

将它们分开

鲍勃做过一次。他有一个网站,显示用户的个人资料,包括他们的姓名和电话号码。他还有一个 API 调用,允许客户端检索具有相同信息的相同配置文件。所以他对网站的 ViewModel 和 API 的 DTO 使用了相同的类。

一开始一切都很好。事实上,业务发展得如此之好,以至于鲍勃能够出售他的股票期权并退休。软件工程部门在很大程度上被外包了,人们并没有真正互相交谈。

一年后,产品负责人在响应客户请求时添加了一项要求,即个人资料页面不仅要显示用户的名字和姓氏,还要显示用户名和电子邮件地址。开发人员通过向 ViewModel 添加 Login 成员并使用 AutoMapper 填充它来完成任务并实现它。他认为 ViewModel 是服务器端代码,并没有考虑太多。

公司推出了直播产品,并且用户名功能取得了成功。只有一个问题。所有 API 客户端现在都在接收 JSON,其中包含用户的登录名、电子邮件地址和其他所有内容,包括他们的哈希密码。

不要成为鲍勃。

【讨论】:

  • 这是一个很好的例子。谢谢!但是,如果我们为应用程序和 MVC 设置单独的 DTO,则可以解决此问题。那么,为什么要有 ViewModel?
  • 如果它们是分开的,那么可以,您可以在 MVC 视图中使用“DTO”。虽然我以为他们叫models.6|12/2
【解决方案2】:

我可以分享我在项目中实施此模式的经验。将该项目视为具有分布式架构的简单 CRUD 应用程序,分为三个解决方案:

  • Project.Web(MVC 应用程序)
  • Project.DTO(纯 C# 类)
  • Project.API(Web API 应用程序)

Project.Web 包含应用程序的 UI 逻辑,并且依赖于 Project.API 进行所有 CRUD 操作,因为与数据库相关的操作是在 Project.API 中执行的。

现在是 Project.DTO,它包含普通的 C# 类,用于来回传输数据。

Project.Web Project.API

为了使其更加分散,我创建了 Project.DTO 作为 Nuget 包并将其托管在 Artifactory 中(您可以使用 Nuget 或任何其他存储库)并使用 Nuget 包管理器使用它。这种方法的主要优点是 DTO 类始终是版本化的并且易于使用。

关于保持 View Model 和 DTO 分离的问题,我可以看到以下几点支持它:

  • 从 API 到 Web 的数据传输,反之亦然:它可能很大而且很复杂。说我的 应用程序想要创建一个客户端并将其所有详细信息添加到 数据库,例如客户地址、客户通信、客户历史 等等。在 Project.Web 中,我们可以有其他的细节,比如 Session 相关数据,不需要传输的 UI 特定数据 从 Web 到 API。因此,创建一个单独的 DTO 是有意义的 仅传输 Web 和 API 通用的此类数据,并且 独立于项目。
  • 对 API 或 Web 的传入请求:假设我创建了一个移动应用程序并准备使用 Project.API。如果我没有创建单独的 View Model 和 DTO,我应该将我的 ViewModel 暴露给客户端(移动应用程序),这是不可取的,因为它可能包含应该保密的敏感字段。
  • 关注点分离:保留您的 DTO 仅用于传递数据,对于应用程序内的任何其他进程,请使用 ViewModel。保持关注点分离原则。

这些是我能想到的与您的问题相关的几点。

【讨论】:

    【解决方案3】:

    两者都是具体的类,看起来相同,但它们的行为和目的不同。

    我们使用 DTO 是因为它

    • 删除循环引用。

    • 隐藏客户端不应查看的特定属性。

    • 省略一些属性以减小负载大小。

    • 扁平化包含嵌套对象的对象图,使它们更方便客户使用。

    • 避免“过度发布”漏洞。

    • 将服务层与数据库层分离。

    那么基本上有什么区别

    • DTO 用于传输数据
    • ViewModel 用于向最终用户显示数据。

    这个术语很简单,因为您的 ViewModel 是经常变化的(按需)。

    假设你有一个CustomerTable (FirstName, LastName, Age, Gender, DOB)

    您将使用上述所有属性制作 DTO。现在,如果此 DTO 正在一个或多个层中使用,您可以简单地将其引用到这些层。

    但在您的 UI 层中,您只想显示客户的 FullName 、 Gender 以及 Age Calculated。

    您将使用最小化的数据创建 ViewModel CustomerViewModel(FullName,Gender, Age),以应对未来频繁更改的可能性。

    • 全名 - 来自 DTO 的名字 + 姓氏
    • 性别 - 来自 DTO 的性别
    • 年龄 - 根据 DTO 计算

    查看更多

    https://docs.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5

    【讨论】:

      猜你喜欢
      • 2013-04-21
      • 2021-02-27
      • 2021-05-30
      • 2021-07-10
      • 2021-06-13
      • 2014-04-27
      • 2021-05-25
      • 1970-01-01
      • 2020-02-12
      相关资源
      最近更新 更多