.NET Repository Pattern
A guide for implementing the Repository pattern that abstracts the data access layer.
- Project Structure
MyApp/ ├── Program.cs ├── App.cs ├── Models/ │ └── User.cs ├── Repositories/ │ ├── IUserRepository.cs │ └── UserRepository.cs ├── Services/ │ ├── IUserService.cs │ └── UserService.cs └── GlobalUsings.cs
- Model Definition
namespace MyApp.Models;
public sealed record User(int Id, string Name, string Email);
- Repository Layer
3.1 Interface
namespace MyApp.Repositories;
public interface IUserRepository { Task<List<User>> GetAllAsync(); Task<User?> GetByIdAsync(int id); Task AddAsync(User user); Task UpdateAsync(User user); Task DeleteAsync(int id); }
3.2 Implementation
namespace MyApp.Repositories;
public sealed class UserRepository : IUserRepository { private readonly List<User> _users = [];
public Task<List<User>> GetAllAsync()
{
return Task.FromResult(_users.ToList());
}
public Task<User?> GetByIdAsync(int id)
{
return Task.FromResult(_users.FirstOrDefault(u => u.Id == id));
}
public Task AddAsync(User user)
{
_users.Add(user);
return Task.CompletedTask;
}
public Task UpdateAsync(User user)
{
var index = _users.FindIndex(u => u.Id == user.Id);
if (index >= 0) _users[index] = user;
return Task.CompletedTask;
}
public Task DeleteAsync(int id)
{
_users.RemoveAll(u => u.Id == id);
return Task.CompletedTask;
}
}
- Service Layer
4.1 Interface
namespace MyApp.Services;
public interface IUserService { Task<IReadOnlyList<User>> GetAllUsersAsync(); Task<User?> GetUserByIdAsync(int id); }
4.2 Implementation
namespace MyApp.Services;
public sealed class UserService(IUserRepository repository) : IUserService { private readonly IUserRepository _repository = repository;
public async Task<IReadOnlyList<User>> GetAllUsersAsync()
{
var users = await _repository.GetAllAsync();
return users.AsReadOnly();
}
public Task<User?> GetUserByIdAsync(int id)
{
return _repository.GetByIdAsync(id);
}
}
- DI Registration
var host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { // Register Repository services.AddSingleton<IUserRepository, UserRepository>();
// Register Service
services.AddSingleton<IUserService, UserService>();
services.AddSingleton<App>();
})
.Build();
6. Generic Repository (Optional)
public interface IRepository<T> where T : class { Task<List<T>> GetAllAsync(); Task<T?> GetByIdAsync(int id); Task AddAsync(T entity); Task UpdateAsync(T entity); Task DeleteAsync(int id); }
- Layer Structure
App (Presentation) ↓ Service Layer (Business Logic) ↓ Repository Layer (Data Access) ↓ Data Source (DB, API, File, etc.)
- Core Principles
-
Repository handles data access only
-
Business logic goes in Service
-
Abstract with interfaces for testability
-
Use Constructor Injection for dependencies