Clean architecture is a robust design approach that enhances maintainability, scalability, and testability. In ASP.NET Core, this methodology involves organizing the application into distinct layers.
In this example, we will use the following layers:
- Presentation Layer: Contains the API controllers. It should reference the Application and Infrastructure projects.
- Application Layer: Contains application services, DTOs (data transfer objects), and mappers. It should reference the Domain project.
- Domain Layer: Contains application-independent business logic.
- Infrastructure Layer: Contains DbContexts, EF Core migrations. It should reference the Application project.
Here is a sample to get clear understanding of Clean Architecture of webapi.
Step 1: Create the solution and projects for Sports Management System.
For webapi solution create a project of ASP.NET Core Web API solution. And the other three solution for Class library solution.
Step 2: Define a model for Sports in domain layer
using System.ComponentModel.DataAnnotations;
namespace SportsManagementSystem.Domain
{
public class Sports
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
}
Step 3: Implement interfaces and service classes in Application layer
using SportsManagementSystem.Domain;
namespace SportsManagementSystem.Application.Interface
{
public interface ISport
{
Task<IEnumerable<Sports>> GetSportsAsync();
Task<Sports> CreateSportAsync(Sports sport);
Task<Sports> GetSportByIdAsync(int id);
Task<Sports> UpdateSportAsync(int id, Sports sport);
Task<Sports> DeleteSportAsync(int id);
}
}
using Microsoft.EntityFrameworkCore;
using SportsManagementSystem.Application.Interface;
using SportsManagementSystem.Domain;
using SportsManagementSystem.Infrastructure;
namespace SportsManagementSystem.Application.Services
{
public class SportService : ISport
{
private readonly ApplicationDbContext _context;
public SportService(ApplicationDbContext context)
{
_context = context;
}
public async Task<IEnumerable<Sports>> GetSportsAsync()
{
return await _context.Sports.ToListAsync();
}
public async Task<Sports> CreateSportAsync(Sports sport)
{
_context.Sports.Add(sport);
await _context.SaveChangesAsync();
return sport;
}
public async Task<Sports> GetSportByIdAsync(int id)
{
var sport = await _context.Sports.FindAsync(id);
return sport;
}
public async Task<Sports> UpdateSportAsync(int id, Sports sport)
{
var data = await _context.Sports.FindAsync(id);
if (data == null)
{
return null;
}
data.Name = sport.Name;
await _context.SaveChangesAsync();
return data;
}
public async Task<Sports> DeleteSportAsync(int id)
{
var sport = await _context.Sports.FindAsync(id);
if (sport == null)
{
return null;
}
_context.Sports.Remove(sport);
await _context.SaveChangesAsync();
return sport;
}
}
}
Step 4: Implement DbContext in Infrastructure layer
using Microsoft.EntityFrameworkCore;
using SportsManagementSystem.Domain;
namespace SportsManagementSystem.Infrastructure
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
public DbSet<Sports> Sports { get; set; }
}
}
Step 5: Implement controller in WebAPI layer
using Microsoft.AspNetCore.Mvc;
using SportsManagementSystem.Application.Interface;
using SportsManagementSystem.Domain;
namespace SportsManagementSystem.WebApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SportsController : ControllerBase
{
private readonly ISport _sportService;
public SportsController(ISport sportService)
{
_sportService = sportService;
}
[HttpGet("Getsports")]
public async Task<ActionResult<IEnumerable<Sports>>> GetSports()
{
var sports = await _sportService.GetSportsAsync();
return Ok(sports);
}
[HttpPost("CreateSports")]
public async Task<ActionResult<Sports>> CreateSport([FromBody] Sports sport)
{
var newSport = await _sportService.CreateSportAsync(sport);
return Ok(newSport);
}
[HttpGet("Getsports/{id}")]
public async Task<ActionResult<Sports>> GetSport(int id)
{
var sport = await _sportService.GetSportByIdAsync(id);
if (sport == null)
{
return NotFound();
}
return Ok(sport);
}
[HttpPut("UpdateSport/{id}")]
public async Task<IActionResult> UpdateSport(int id, [FromBody] Sports sport)
{
var updatedSport = await _sportService.UpdateSportAsync(id, sport);
if (updatedSport == null)
{
return NotFound();
}
return Ok();
}
[HttpDelete("DeleteSport/{id}")]
public async Task<IActionResult> DeleteSport(int id)
{
var deletedSport = await _sportService.DeleteSportAsync(id);
if (deletedSport == null)
{
return NotFound();
}
return Ok();
}
}
}
Step 6: Configure Dependency injection in program.cs
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("dbconn")));
builder.Services.AddScoped<ISport, SportService>();
Step 7: Run the Application.
This example demonstrates a simple Clean Architecture setup with separation of concerns, independent layers, and a clear flow of dependencies. It allows for easy testing, maintenance, and scalability.
Conclusion
Clean Architecture in a .NET Core Web API provides a solid foundation for building scalable, maintainable, and testable applications. Key principles include the separation of concerns, testability, flexibility, scalability, and adherence to the Dependency Inversion Principle.
By organizing the application into distinct layers and keeping the core business logic independent of external frameworks, Clean Architecture promotes maintainability and adaptability to changing requirements. Real-world considerations, community resources, and continuous learning play crucial roles in mastering and effectively applying Clean Architecture principles.
Overall, adopting Clean Architecture sets the stage for high-quality software development and long-term success.
No Comment! Be the first one.