Map transport DTOs to domain models behind a repository abstraction.
// Domain/Models/Todo.cs
public sealed record Todo(string Id, string Title, bool Done);
// Domain/Abstractions/ITodosRepository.cs
public interface ITodosRepository { Task<IReadOnlyList<Todo>> ListAsync(CancellationToken ct); }
// Infrastructure/Http/TodoDto.cs
public sealed class TodoDto { public string Id { get; set; } = default!; public string Title { get; set; } = default!; public bool Completed { get; set; } }
// Infrastructure/Http/HttpTodosRepository.cs
public sealed class HttpTodosRepository(HttpClient http) : ITodosRepository
{
public async Task<IReadOnlyList<Todo>> ListAsync(CancellationToken ct)
{
using var res = await http.GetAsync("/todos", ct);
res.EnsureSuccessStatusCode();
var stream = await res.Content.ReadAsStreamAsync(ct);
var dtos = await JsonSerializer.DeserializeAsync<List<TodoDto>>(stream, cancellationToken: ct) ?? [];
return dtos.Select(d => new Todo(d.Id, d.Title, d.Completed)).ToList();
}
}
// API/Program.cs
builder.Services.AddHttpClient<ITodosRepository, HttpTodosRepository>(c => c.BaseAddress = new Uri("https://example.com"));
Register a typed HttpClient for the repository and expose a minimal API endpoint.
// Program.cs (Minimal API)
using Domain.Abstractions; // your interface namespace
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient<ITodosRepository, HttpTodosRepository>(c =>
{
c.BaseAddress = new Uri("https://jsonplaceholder.typicode.com");
});
var app = builder.Build();
app.MapGet("/todos", async (ITodosRepository repo, CancellationToken ct)
=> await repo.ListAsync(ct));
app.Run();
// Infrastructure/Http/HttpTodosRepository.cs (mapping example)
public sealed class HttpTodosRepository(HttpClient http) : ITodosRepository
{
public async Task<IReadOnlyList<Todo>> ListAsync(CancellationToken ct)
{
using var res = await http.GetAsync("/todos?_limit=10", ct);
res.EnsureSuccessStatusCode();
var stream = await res.Content.ReadAsStreamAsync(ct);
var dtos = await JsonSerializer.DeserializeAsync<List<TodoDto>>(stream, cancellationToken: ct) ?? [];
return dtos.Select(d => new Todo(d.Id, d.Title, d.Completed)).ToList();
}
}
Notes
Paste into a Minimal API project (see sandboxes/dotnet-minimal-api):