CodexBloom - Programming Q&A Platform

Best practices for separating concerns in ASP.NET Core MVC with a focus on clean architecture

๐Ÿ‘€ Views: 97 ๐Ÿ’ฌ Answers: 1 ๐Ÿ“… Created: 2025-10-08
asp.net-core clean-architecture mediator-pattern C#

I'm working through a tutorial and Building an application that manages employee records using ASP.NET Core MVC, I want to ensure that I'm following clean architecture principles. My goal is to keep the layers of my application clearly defined: presentation, business logic, and data access. Currently, I have the following structure: - Controllers - Services - Repositories In my controller, I am directly calling the service layer, which looks like this: ```csharp public class EmployeeController : Controller { private readonly IEmployeeService _employeeService; public EmployeeController(IEmployeeService employeeService) { _employeeService = employeeService; } public IActionResult Index() { var employees = _employeeService.GetAllEmployees(); return View(employees); } } ``` The service is calling the repository like so: ```csharp public class EmployeeService : IEmployeeService { private readonly IEmployeeRepository _employeeRepository; public EmployeeService(IEmployeeRepository employeeRepository) { _employeeRepository = employeeRepository; } public IEnumerable<Employee> GetAllEmployees() { return _employeeRepository.GetAll(); } } ``` For my repository, Iโ€™m using Entity Framework Core, and the method looks like this: ```csharp public class EmployeeRepository : IEmployeeRepository { private readonly AppDbContext _context; public EmployeeRepository(AppDbContext context) { _context = context; } public IEnumerable<Employee> GetAll() { return _context.Employees.ToList(); } } ``` Now, to enhance separation of concerns, Iโ€™m considering using the Mediator pattern to decouple my controllers from services. The idea is to introduce a command or query handler pattern that would allow me to handle requests through a mediator. Documentation suggests using the `MediatR` library, which looks promising. Hereโ€™s what I think it might look like: ```csharp public class GetEmployeesQuery : IRequest<IEnumerable<Employee>> { } public class GetEmployeesQueryHandler : IRequestHandler<GetEmployeesQuery, IEnumerable<Employee>> { private readonly IEmployeeRepository _repository; public GetEmployeesQueryHandler(IEmployeeRepository repository) { _repository = repository; } public async Task<IEnumerable<Employee>> Handle(GetEmployeesQuery request, CancellationToken cancellationToken) { return await _repository.GetAllAsync(); } } ``` In my `Startup.cs`, Iโ€™d register the MediatR services like this: ```csharp services.AddMediatR(typeof(Startup)); ``` After implementing this, the controller would change to: ```csharp public class EmployeeController : Controller { private readonly IMediator _mediator; public EmployeeController(IMediator mediator) { _mediator = mediator; } public async Task<IActionResult> Index() { var employees = await _mediator.Send(new GetEmployeesQuery()); return View(employees); } } ``` Iโ€™m also aware that using AutoMapper could simplify the data transformation from DTOs to entities, and vice versa, but Iโ€™m not quite sure where to implement that effectively. Should I map in the service layer or directly in the controllers? Was hoping to get some insights from those more experienced in implementing clean architecture in ASP.NET Core MVC applications. What are the common pitfalls, and how can I ensure that Iโ€™m adhering to best practices while keeping the application maintainable and scalable? This is my first time working with C# 3.11. Am I approaching this the right way?