Veri Aktarımı Nesneleri (DTO) OluşturmaCreate Data Transfer Objects (DTOs)

, Mike te sonby Mike Wasson

Tamamlanmış projeyi indirDownload Completed Project

Şu anda Web API 'imiz, veritabanı varlıklarını istemciye kullanıma sunuyor.Right now, our web API exposes the database entities to the client. İstemci doğrudan veritabanı tablolarınıza eşleyen verileri alır.The client receives data that maps directly to your database tables. Bununla birlikte, her zaman iyi bir fikir değildir.However, that's not always a good idea. Bazen istemciye göndereceğiniz verilerin şeklini değiştirmek isteyebilirsiniz.Sometimes you want to change the shape of the data that you send to client. Örneğin, şunları yapmak isteyebilirsiniz:For example, you might want to:

  • Döngüsel başvuruları Kaldır (önceki bölüme bakın).Remove circular references (see previous section).
  • İstemcilerin görüntülemesi beklenen belirli özellikleri gizleyin.Hide particular properties that clients are not supposed to view.
  • Yük boyutunu azaltmak için bazı özellikleri atlayın.Omit some properties in order to reduce payload size.
  • İstemcilere daha uygun hale getirmek için iç içe geçmiş nesneler içeren nesne grafiklerini düzleştirin.Flatten object graphs that contain nested objects, to make them more convenient for clients.
  • "Aşırı gönderme" güvenlik açıklarını önleyin.Avoid "over-posting" vulnerabilities. (Bkz. Yük nakli hakkında bir tartışma için model doğrulama .)(See Model Validation for a discussion of over-posting.)
  • Hizmet katmanınızı veritabanı katmanınızdan ayırın.Decouple your service layer from your database layer.

Bunu gerçekleştirmek için bir veri aktarımı nesnesi (DTO) tanımlayabilirsiniz.To accomplish this, you can define a data transfer object (DTO). Bir DTO, verilerin ağ üzerinden nasıl gönderileceğini tanımlayan bir nesnedir.A DTO is an object that defines how the data will be sent over the network. Bunun, kitap varlığıyla nasıl çalıştığını görelim.Let's see how that works with the Book entity. Modeller klasöründe, iki DTO sınıfı ekleyin:In the Models folder, add two DTO classes:

namespace BookService.Models
{
    public class BookDto
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string AuthorName { get; set; }
    }
}

namespace BookService.Models
{
    public class BookDetailDto
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public int Year { get; set; }
        public decimal Price { get; set; }
        public string AuthorName { get; set; }
        public string Genre { get; set; }
    }
}

BookDetailDto sınıfı, kitabın yazar adını tutan bir dize olması AuthorName dışında, kitap modelindeki tüm özellikleri içerir.The BookDetailDto class includes all of the properties from the Book model, except that AuthorName is a string that will hold the author name. BookDto sınıfı BookDetailDtobir özellikler alt kümesini içerir.The BookDto class contains a subset of properties from BookDetailDto.

Sonra, BooksController sınıfındaki iki GET yöntemini DTOs döndüren sürümlerle değiştirin.Next, replace the two GET methods in the BooksController class, with versions that return DTOs. Kitap varlıklarından DTOs 'a dönüştürmek için LINQ Select ifadesini kullanacağız.We'll use the LINQ Select statement to convert from Book entities into DTOs.

// GET api/Books
public IQueryable<BookDto> GetBooks()
{
    var books = from b in db.Books
                select new BookDto()
                {
                    Id = b.Id,
                    Title = b.Title,
                    AuthorName = b.Author.Name
                };

    return books;
}

// GET api/Books/5
[ResponseType(typeof(BookDetailDto))]
public async Task<IHttpActionResult> GetBook(int id)
{
    var book = await db.Books.Include(b => b.Author).Select(b =>
        new BookDetailDto()
        {
            Id = b.Id,
            Title = b.Title,
            Year = b.Year,
            Price = b.Price,
            AuthorName = b.Author.Name,
            Genre = b.Genre
        }).SingleOrDefaultAsync(b => b.Id == id);
    if (book == null)
    {
        return NotFound();
    }

    return Ok(book);
}

Yeni GetBooks yöntemi tarafından oluşturulan SQL aşağıda verilmiştir.Here is the SQL generated by the new GetBooks method. EF 'in LINQ seçimini BIR SQL SELECT ifadesine dönüştürdüğünde emin olabilirsiniz.You can see that EF translates the LINQ Select into a SQL SELECT statement.

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Title] AS [Title], 
    [Extent2].[Name] AS [Name]
    FROM  [dbo].[Books] AS [Extent1]
    INNER JOIN [dbo].[Authors] AS [Extent2] ON [Extent1].[AuthorId] = [Extent2].[Id]

Son olarak, PostBook yöntemini bir DTO döndürecek şekilde değiştirin.Finally, modify the PostBook method to return a 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);
}

Note

Bu öğreticide, kodda el ile DTOs 'a dönüştürüyoruz.In this tutorial, we're converting to DTOs manually in code. Diğer bir seçenek de, dönüştürmeyi otomatik olarak işleyen Automaber gibi bir kitaplık kullanmaktır.Another option is to use a library like AutoMapper that handles the conversion automatically.