屏幕DTO应该位于哪个项目层?

11
我有一个项目,在该项目中我们使用屏幕DTO来封装服务层表示层之间的数据。在我们的情况下,表示层是ASP.Net。
唯一知道DTO的类是服务层类和调用这些服务并显示DTO的页面/控件。
DTO几乎总是特定于页面/控件的,因此我认为它们属于表示层,但这意味着服务层必须引用表示层才能使用DTO。
我几乎认为服务层应该返回更丰富的对象(但不是域实体?),然后表示层可以获取这些对象并将它们映射到针对每个页面/控件关注的具体DTO。
这是一个接口声明和一个DTO,你可以看看我在说什么:
public interface IBlogTasks
{
    BlogPostDisplayDTO GetBlogEntryByTitleAndDate(int year, int month, string urlFriendlyTitle);
}

public class BlogPostDisplayDTO 
{
    public string Title { get; set; }
    public DateTime PostDate { get; set; }
    public string HtmlContent { get; set; }
    public string ImageUrl { get; set; }        
    public string Author { get; set; }
    public int CommentCount { get; set; }
    public string Permalink { get; set; }
}   

编辑

这里有另一个代码示例,描述了一个与领域模型无关的用例。也许这会使事情更加清晰。我相信我过度使用了DTO的含义。我并不是在谈论用于在网络上传输对象的功能DTO。我正在创建DTO来规范通信与我的服务层之间的合同。

public interface IAuthenticationTasks
{
    bool AuthenticateUser(AuthenticationFormDTO authDTO);
}

public class AuthenticationFormDTO
{
    public string UserName { get; set; }
    public string Password { get; set; }
    public bool persistLogin { get; set; }
}

假设现在我的身份验证突然需要一个IP地址参数。我现在可以将该属性添加到DTO中,而无需更改我的契约接口。

我不想将实体传递给我的演示层。我不希望我的代码后台有能力执行BlogPost.AddComment(new Comment())

2个回答

18

尽管“DTO”的规范用例更多地是“可通过网络传递的可序列化对象”,但在这种情况下,您实际上更多指的是“表示-传输对象”或“视图模型”。

通常对于我们的项目来说,这些对象存在的位置是映射 DDD 领域模型到 PTO 类的“翻译”代码所在的地方。如果这个代码在表示层(也许不是很好的答案),那么表示层就是我声明 PTO 的地方。但更常见的情况是,服务为您进行翻译,这意味着“服务”和“表示”层都需要引用 PTO,并且通常会导致在一个单独的、中立的项目/程序集/命名空间/任何东西中声明它们,然后表示层和服务层都可以引用它。


谢谢!我觉得我迷惑的部分是在错误的上下文中使用DTO这个术语。PTO和ViewModel给了我一些更好的术语去进一步阅读。 - Scott Muc

4
你是否在使用实际的服务(Web或WCF)?如果是的话,那么请在服务层定义DTO,并且当你添加服务引用时创建的代理将包含所有的DTO类型。这是最简单的方法,只保持了你的ASP.NET项目和服务项目之间的松耦合 - 两个方向都不需要直接项目引用。当你更新DTO时,你只需要更新服务引用,它会自动通过生成的代理类将更新暴露给你的Web项目。
无论如何,如果你遵循像DDD这样的方法,最好让你的基础设施项目(例如特定于Web平台的UI)引用你的领域对象而不是相反。然而,如果你遵循我上面的建议,你的Web项目将没有直接依赖于项目,这是一件好事,肯定比让你的丰富领域对象依赖于你的Web项目要好(即使这是一个考虑因素 - 我知道你并没有说你正在做这个)。
如果你的DTO是视图特定的,则应该将它们包含在你的UI项目中。确保控制器只从模型中获取视图所需的内容 - 在你的情况下,只需一个值对象,其中包含视图所需的字段。

我不是在谈论服务的实现。我的服务层只是 UI 和领域之间的一个薄服务。你说得对,我正在遵循 DDD 方法,但我不会让我的领域实体离开服务层。 - Scott Muc
那么,这将使您的DTOs只是实体对象,没有传输。它们驻留在服务层中,演示文稿根据服务层提供的实体对象创建自己的对象,并且这些对象驻留在演示层。我是对的吗? - Adeel Ansari
我已编辑我的问题,以描述我对DTO的期望使用。 - Scott Muc
我会退而求其次,认为这些DTO是特定于您的UI层,因此应该放在那里。如果您无法创建一种设计,使您的Domain对象依赖于您的基础设施和UI层,则将DTO放入其自己的第三个项目中,并使UI域依赖于该项目。 - ssmith
我更新了我的回答 - 请看最后一段。你希望在UI项目中使用DTOs。你希望你的控制器成为领域对象和视图之间的门卫。这是它的职责。 - ssmith
我想我明白了。所以通过这些层,一个实体从数据访问层传递到服务层,然后将其映射为值对象,接着呈现层获取该对象并将其映射到所有UI所需的显示DTO。 - Scott Muc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接