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())

4

2 回答 2

18

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

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

于 2009-01-30T11:57:29.103 回答
4

您是否使用实际服务(Web 或 WCF)?如果是这样,则在服务层中定义 DTO,当您添加服务(或使用旧 ASMX 的 Web)引用时创建的代理将包含所有 DTO 类型。这是最简单的方法,并且只保持 ASP.NET 项目和服务项目之间的松散耦合——在任何一个方向都不需要直接的项目引用。当您更新 DTO 时,您需要做的就是更新您的服务引用,它会通过生成的代理类自动将更新公开给您的 Web 项目。

无论如何,如果您遵循 DDD 方法之类的方法,最好让您的基础架构项目(例如特定于 Web 平台的 UI)引用您的域对象,反之亦然。但是,如果您遵循我上面的建议,您的 Web 项目根本不会直接依赖于该项目,这是一件好事,而且肯定比让您的富域对象依赖于您的 Web 项目更好(如果这甚至一个考虑 - 我意识到你并没有说你正在这样做)。

如果您的 DTO 是特定于视图的,那么我会将它们包含在您的 UI 项目中。确实应该是控制器的工作,以确保视图仅从模型中获取所需的内容-在您的情况下,它是一个仅包含视图所需字段的值对象。

于 2009-01-30T01:13:34.147 回答