使用模型类与 DTO 发布操作

Mos*_*bdo 5 c# dto asp.net-web-api .net-core asp.net-core

这个 MSDN链接解释了为什么将 DTO 类用于 Web API 是一种很好的做法。这是可以理解的,让我困惑的是在同一页面中,post 方法使用模型类而不是简单的 DTO 类,如下所示:

[ResponseType(typeof(BookDTO))]
public async Task<IHttpActionResult> PostBook(Book book)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    db.Books.Add(book);
    await db.SaveChangesAsync();

    // New code:
    // Load author name
    db.Entry(book).Reference(x => x.Author).Load();

    var dto = new BookDTO()
    {
        Id = book.Id,
        Title = book.Title,
        AuthorName = book.Author.Name
    };

    return CreatedAtRoute("DefaultApi", new { id = book.Id }, dto);
}
Run Code Online (Sandbox Code Playgroud)

我想我的问题是:Post/Put 操作应该采用模型还是 DTO 参数?

更新:从答案来看,即使在 post/put action 的情况下,似乎也建议使用 dto,但这会导致另一个问题,如何在 post action 的情况下从 dto 映射到 Model 类?假设我们使用 AutoMapper,我发现了很多链接,例如thisthis警告不要在反向映射中使用它(即 dto => Model 类)。

Chr*_*att 5

首先,是的,您应该始终使用 DTO。无论你正在处理一个正规的网站或API,你应该永远不会直接保存对象从POST数据实例化。这打开了一个巨大的安全漏洞,人们可以在其中操纵帖子数据并进行各种恶作剧。具有讽刺意味的是,您实际上可以绑定到您的实体类,但如果您这样做了,您不应该保存该实例,而是创建一个新实例,映射来自已发布实例的数据,然后保存您创建的实例 - 重要的是部分从不保存发布的实例。使用视图模型/DTO 只会使您更明显地应该执行等式的映射部分,因此是推荐的方法。

就 AutoMapper 而言,建议不要用于反向映射,因为映射到将要保存到数据库的内容涉及许多细微​​差别。特别是当您涉及实体框架等 ORM 时。您可以使用 AutoMapper,但您只需要了解所有这些细微差别并相应地处理它们。一般来说,无论如何,在这些情况下手动进行映射可能更容易,因为它通常涉及 AutoMapper 之类的配置,从长远来看,您不会为自己节省太多精力。手动映射就像听起来一样。如果您正在创建一个 new Book,那么您只需新建一个Book. 如果您正在修改现有的Book的,则从数据库中提取该实例的实例。无论哪种方式,Book以及一个类似 的实例BookDTO,它是从发布数据创建的。那么你只需:

book.Title = bookDto.Tile;
// etc.
Run Code Online (Sandbox Code Playgroud)

对于诸如作者关系之类的事情,您可能需要进行额外的查询。例如:

var author = _context.Authors.SingleOrDefault(x => x.Name == bookDto.AuthorName);
book.Author = author;
Run Code Online (Sandbox Code Playgroud)