What is Repository Pattern in .NET Core Web API?
In modern software development, maintaining clean, testable, and maintainable code is crucial. When building .NET Core Web API applications, one pattern that helps achieve this is the Repository Pattern.
The Repository Pattern in .NET Core Web API acts as a middle layer between your business logic and data access layer. It abstracts database operations, making your code more modular and easier to test. In this guide, we will explore the repository pattern in depth, understand its advantages, and implement it step-by-step in a .NET Core Web API project.
Understanding the Repository Pattern
The Repository Pattern .NET Core Web API project is a design pattern that isolates data access logic from the rest of the application. It provides a clean API for the business logic to work with, without knowing the underlying database implementation.
Advantages of the Repository Pattern:
- Decoupling: Separates business logic from data access logic.
- Testability: Easy to mock repositories for unit testing.
- Centralized Data Operations: All database operations are in one place.
When to Use:
- For complex applications with multiple data sources.
- When you want to make your code more maintainable and testable.
When Not to Use:
- For simple CRUD operations in small projects, it may add unnecessary complexity.
Types of Repositories
- Generic Repository:
A reusable repository that handles CRUD operations for multiple entities.
Example:IGenericRepository<T>with methods likeAdd,Get,Update,Delete. - Specific Repository:
Tailored for a single entity with custom operations beyond basic CRUD.
Example:IProductRepositoryforProductentity withGetProductsByCategory()method.
- Generic repositories reduce repetitive code and Specific repositories allow more control for entity-specific logic.
Setting Up a Sample .NET Core Web API Project

Now, we will see the use of repository pattern in .NET Core Web API in action. Follow the steps below:
- Create a new .NET Core Web API project in Visual Studio or via CLI:
dotnet new webapi -n RepositoryDemo
cd RepositoryDemo
- Install Entity Framework Core:
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
- Organize your project structure:
/Controllers
/Models
/Repositories
/Services
/Data
Implementing the Repository Pattern
Step 1: Create Models
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Step 2: Define Repository Interfaces
Generic Repository Interface
public interface IGenericRepository<T> where T : class
{
Task<IEnumerable<T>> GetAllAsync();
Task<T> GetByIdAsync(int id);
Task AddAsync(T entity);
void Update(T entity);
void Delete(T entity);
}
Specific Repository Interface
public interface IProductRepository : IGenericRepository<Product>
{
Task<IEnumerable<Product>> GetProductsByCategory(string category);
}
Step 3: Implement Repository Classes
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private readonly AppDbContext _context;
public GenericRepository(AppDbContext context) => _context = context;
public async Task<IEnumerable<T>> GetAllAsync() => await _context.Set<T>().ToListAsync();
public async Task<T> GetByIdAsync(int id) => await _context.Set<T>().FindAsync(id);
public async Task AddAsync(T entity) => await _context.Set<T>().AddAsync(entity);
public void Update(T entity) => _context.Set<T>().Update(entity);
public void Delete(T entity) => _context.Set<T>().Remove(entity);
}
Step 4: Register Repositories in DI Container
builder.Services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));
builder.Services.AddScoped<IProductRepository, ProductRepository>();
Step 5: Use Repository in Controllers
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductRepository _productRepo;
public ProductsController(IProductRepository productRepo) => _productRepo = productRepo;
[HttpGet]
public async Task<IActionResult> GetProducts() => Ok(await _productRepo.GetAllAsync());
}
Unit Testing with Repository Pattern
The repository pattern allows mocking data access for unit testing.
var mockRepo = new Mock<IProductRepository>();
mockRepo.Setup(repo => repo.GetAllAsync()).ReturnsAsync(GetTestProducts());
- This ensures tests don’t rely on a real database.
Best Practices
Keep repositories focused on a single responsibility.
- Avoid business logic inside repositories.
- Use async/await for database calls.
- Follow clear naming conventions:
IEntityRepository,GenericRepository<T>.
Common Mistakes to Avoid
- Overusing generic repositories for all operations.
- Tight coupling between controller and repository.
- Ignoring async programming, which can lead to performance issues.
Conclusion
Implementing the Repository Pattern in .NET Core Web API helps create maintainable, testable, and clean applications. By abstracting data access, your business logic stays decoupled and easier to manage.
Start by implementing a generic repository for CRUD operations and expand with specific repositories as needed. The repository pattern is a small change with huge benefits in the long run. Here we have used Dependency Injection. If you want to explore about DI, go through this post : Understanding Dependency Injection in .NET Core with Practical Examples
Thanks for reading.

