reading-notes

View on GitHub

Data Transfer Objects

Table of contents

Read No. Name of chapter
16 Create Data Transfer Objects (DTOs)
16 How to use Data Transfer Objects in ASP.NET Core

Create Data Transfer Objects (DTOs)

Right now, our web API exposes the database entities to the client. The client receives data that maps directly to your database tables. However, that’s not always a good idea. Sometimes you want to change the shape of the data that you send to client. For example, you might want to:

To accomplish this, you can define a data transfer object (DTO). A DTO is an object that defines how the data will be sent over the network. Let’s see how that works with the Book entity. 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; }
    }
}

The BookDetailDto class includes all of the properties from the Book model, except that AuthorName is a string that will hold the author name. The BookDto class contains a subset of properties from BookDetailDto.

Next, replace the two GET methods in the BooksController class, with versions that return DTOs. 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);
}

Here is the SQL generated by the new GetBooks method. 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]

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);
}

How to use Data Transfer Objects in ASP.NET Core

A Data Transfer Object (commonly known as a DTO) is usually an instance of a POCO (plain old CLR object) class used as a container to encapsulate data and pass it from one layer of the application to another. You would typically find DTOs being used in the service layer to return data back to the presentation layer. The biggest advantage of using DTOs is decoupling clients from your internal data structures.

Why use Data Transfer Objects (DTOs)?

When designing and developing an application, if you’re using models to pass data between the layers and sending data back to the presentation layer, then you’re exposing the internal data structures of your application. That’s a major design flaw in your application.

By decoupling your layers DTOs make life easier when you’re implementing APIs, MVC applications, and also messaging patterns such as Message Broker. A DTO is a great choice when you would like to pass a lightweight object across the wire — especially when you’re passing your object via a medium that is bandwidth-constrained.

Use DTOs for data hiding

Another reason you would want to use DTOs is data hiding. That is, by using DTOs you can return only the data requested. As an example, assume you have a method named GetAllEmployees() that returns all the data pertaining to all employees. Let’s illustrate this by writing some code.

In the project we created earlier, create a new file called Employee.cs. Write the following code inside this file to define a model class named Employee.

public class Employee
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string DepartmentName { get; set; }
        public decimal Basic { get; set; }
        public decimal DA { get; set; }
        public decimal HRA { get; set; }
        public decimal NetSalary { get; set; }
    }

Note the Employee class contains properties including Id, FirstName, LastName, Department, Basic, DA, HRA, and NetSalary. However, the presentation layer might only need the Id, FirstName, LastName, and Department Name of the employees from the GetAllEmployees() method. If this method returns a List< Employee> then anyone would be able to see the salary details of an employee. You don’t want that.

To avoid this problem, you might design a DTO class named EmployeeDTO that would contain only the properties that are requested (such as Id, FirstName, LastName, and Department Name).

Create a DTO class in C#

To achieve this, create a file named EmployeeDTO.cs and write the following code in there.

public class EmployeeDTO
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string DepartmentName { get; set; }
    }

Now that the model and data transfer object classes are available, you might want to create a converter class that contains two methods: one to convert an instance of the Employee model class to an instance of EmployeeDTO and (vice versa) one to convert an instance of EmployeeDTO to an instance of the Employee model class. You might also take advantage of AutoMapper, a popular object-to-object mapping library to map these two dissimilar types.

You should create a List< EmployeeDTO> in the service layer of your application and return the collection back to the presentation layer.