The Repository Pattern in ASP.NET Core is a design pattern that mediates data access logic and business logic by providing a centralized place to perform data access operations. It abstracts the data layer, allowing the business logic to interact with the data source through a well-defined interface.
Why Use the Repository Pattern
- Abstraction: It abstracts the data access code, providing a clean separation between data and business logic.
- Testability: It improves testability by allowing you to mock the data access layer.
- Maintainability: It centralizes data access logic, making it easier to manage and modify.
- Consistency: It ensures consistent data access logic and helps enforce coding standards.
Major Benefits
- Separation of Concerns: Keeps data access logic separate from business logic.
- Loose Coupling: Reduces dependencies between different parts of the application.
- Code Reusability: Encourages reuse of data access logic across multiple services.
- Unit Testing: Facilitates unit testing by allowing the data access layer to be mocked.
Example
Here's an example of implementing the Repository Pattern in an ASP.NET Core application.
Step 1: Define the Service Interface
public interface IProductService
{
Task<IEnumerable<Product>> GetAllProductsAsync();
Task<Product> GetProductByIdAsync(int id);
Task CreateProductAsync(Product product);
Task UpdateProductAsync(Product product);
Task DeleteProductAsync(int id);
}
Step 2: Implement the Service
public class ProductService : IProductService
{
private readonly IProductRepository _productRepository;
public ProductService(IProductRepository productRepository)
{
_productRepository = productRepository;
}
public async Task<IEnumerable<Product>> GetAllProductsAsync()
{
// Business logic can be added here
return await _productRepository.GetAllAsync();
}
public async Task<Product> GetProductByIdAsync(int id)
{
// Business logic can be added here
return await _productRepository.GetByIdAsync(id);
}
public async Task CreateProductAsync(Product product)
{
// Business logic such as validation can be added here
await _productRepository.AddAsync(product);
}
public async Task UpdateProductAsync(Product product)
{
// Business logic such as validation can be added here
await _productRepository.UpdateAsync(product);
}
public async Task DeleteProductAsync(int id)
{
// Business logic can be added here
await _productRepository.DeleteAsync(id);
}
}
Step 3: Register the Service in the Dependency Injection Container
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IProductRepository, ProductRepository>();
services.AddScoped<IProductService, ProductService>();
}
Step 4: Use the Service in the Controller
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Product>>> GetProducts()
{
var products = await _productService.GetAllProductsAsync();
return Ok(products);
}
[HttpGet("{id}")]
public async Task<ActionResult<Product>> GetProduct(int id)
{
var product = await _productService.GetProductByIdAsync(id);
if (product == null)
{
return NotFound();
}
return Ok(product);
}
[HttpPost]
public async Task<ActionResult> CreateProduct(Product product)
{
await _productService.CreateProductAsync(product);
return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, product);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateProduct(int id, Product product)
{
if (id != product.Id)
{
return BadRequest();
}
await _productService.UpdateProductAsync(product);
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduct(int id)
{
await _productService.DeleteProductAsync(id);
return NoContent();
}
}
Summary
- Repository: Handles data access logic.
- Service: Contains business logic and uses the repository for data access.
- Controller: Interacts with the service to fulfill HTTP requests.
By adding a service layer, you encapsulate business logic within the service, keeping the controller focused on handling HTTP requests and responses. This approach ensures a clean separation of concerns and enhances maintainability and testability.
Tags
Asp.net Core