Getting Started with DTOs

A DTO is a plain C# class used to transfer data between layers (e.g., from your API to your Blazor client). It helps decouple your internal models from what you expose externally.

Create DTOs in a Shared Project

To share DTOs between your Blazor WASM and API:

  • Create a Shared project (e.g., MyApp.Shared)
  • Add DTO classes there so both the Blazor client and API can reference them.
// MyApp.Shared/DTOs/ProductDto.cs
public class ProductDto
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
}

In your ASP.NET Core Web API:

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public ActionResult<List<ProductDto>> GetProducts()
    {
        var products = new List<ProductDto>
        {
            new ProductDto { Id = 1, Name = "Widget", Price = 9.99M },
            new ProductDto { Id = 2, Name = "Gadget", Price = 19.99M }
        };
        return Ok(products);
    }

In your Blazor client project:

@inject HttpClient Http

@code {
    private List<ProductDto>? products;

    protected override async Task OnInitializedAsync()
    {
        products = await Http.GetFromJsonAsync<List<ProductDto>>("api/products");
    }
}

Or use a service class:

public class ProductService
{
    private readonly HttpClient _http;

    public ProductService(HttpClient http)
    {
        _http = http;
    }

    public async Task<List<ProductDto>?> GetProductsAsync()
    {
        return await _http.GetFromJsonAsync<List<ProductDto>>("api/products");
    }
}

Tips for DTO Design

  • Keep DTOs flat and simple.
  • Avoid exposing domain entities directly.
  • Use nullable types if fields may be missing.
  • Use records if immutability is preferred: