liveBook · Manning

Data transfer object

As explained in Building Distributed Applications that Work

A data transfer object is a data-only structure that carries selected values across application or service boundaries.

A data transfer object (DTO) carries data between services or between a client and a server. In an online shop, the API returns product DTOs to the UI. The DTO contains the values the UI needs to display, while the database entity can retain fields used for storage, such as its identity field. section 3.2.1

namespace OnlineShop.ServiceDefaults.Dtos;

public record ProductDto(
    string Title,
    string Summary,
    decimal Price
);

ProductDto is a C# record containing Title, Summary, and Price. Unlike the Product entity, it has no database identity or DateAdded field. section 3.2.1

The separate type keeps the UI database-agnostic: the API can change its database implementation without requiring the presentation layer to work with database entities. Both sides exchange the product-shaped DTO instead. section 3.2.2

Listing 3.1 HTTP client for retrieving product data
using OnlineShop.ServiceDefaults.Dtos;

namespace OnlineShop.Web;

public class ProductsApiClient(HttpClient httpClient)
{
    public async Task<ProductDto[]> GetProductsAsync(int maxItems = 10, CancellationToken cancellationToken = default)
    {
        List<ProductDto>? products= null;
        await foreach (var product in
httpClient.GetFromJsonAsAsyncEnumerable<ProductDto>(
  		"/products", cancellationToken))            #1
        {
            if (products?.Count >= maxItems)    #2
            {
                break;
            }
            if (product is not null)
            {
                products ??= [];
                products.Add(product);
            }
        }

        return products?.ToArray() ?? [];   #3
    }
}

ProductsApiClient requests /products and reads the JSON response as ProductDto values, returning up to the requested number of products. section 3.2.2

Listing 3.2 Home page displaying the product data
@page "/"
@using OnlineShop.ServiceDefaults.Dtos
@attribute [StreamRendering(true)]
@attribute [OutputCache(Duration = 5)]

@inject ProductsApiClient ProductsApi

<PageTitle>Products</PageTitle>

<h1>Products</h1>

@if (products == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Name</th>
                <th>Price (USD)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var product in products)
            {
                <tr>
                    <td>@product.Title</td>
                    <td>@product.Price</td>
                    <td>@product.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private ProductDto[]? products;

    protected override async Task OnInitializedAsync()
    {
        products = await ProductsApi.GetProductsAsync();
    }
}

The home page consumes those DTOs and renders each product’s title, price, and summary. section 3.2.2

How Building Distributed Applications that Work covers it

How deep it goes
Defines the DTO’s boundary role and shows a C# record and consuming client, but does not detail entity-to-DTO conversion.
Examples
Uses a ProductDto record, a /products HTTP request, and a home-page product table.
What it assumes
Introduces the distinction between database entities and DTOs while using C# types and an existing API-to-UI workflow.
What you can do after
Build it from scratch as a C# product record, then use it to receive and display API data.
How it connects
Links database entities, APIs, HTTP clients, and separation of concerns through a shared data shape.

Also explained in

Compare how 6 books explain data transfer object →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Building Distributed Applications that Work. The section links point to the parts of the book it draws on.