Welcome to the pinnacle of the ASP.NET Core MVC Mastery course. Everything you've learned—Dependency Injection, Entity Framework Core, Repositories, ViewModels, Validations, and Security—will now seamlessly converge into a fully functional, production-ready Employee Management System. This isn't just theory; this is the exact architecture you will build in enterprise environments.
We will construct an N-Tier monolithic application respecting Clean Architecture boundaries. This ensures testability and separation of concerns.
IEmployeeRepository.public class Employee
{
public int Id { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public DateTime DateOfJoining { get; set; }
public decimal Salary { get; set; }
// Establishing a 1-to-Many Relationship
public int DepartmentId { get; set; }
public Department Department { get; set; }
}
// The contract the database implementation must fulfill
public interface IEmployeeRepository
{
Task<IEnumerable<Employee>> GetAllEmployeesAsync();
Task<Employee> GetEmployeeByIdAsync(int id);
Task AddEmployeeAsync(Employee employee);
Task UpdateEmployeeAsync(Employee employee);
Task DeleteEmployeeAsync(int id);
}
For operations like Creating an employee, we explicitly dictate required fields using ViewModels and FluentValidation.
public class EmployeeCreateViewModel
{
[Required(ErrorMessage = "Please provide a name")]
[StringLength(100, MinimumLength = 2)]
public string FullName { get; set; }
[Required]
[EmailAddress]
// Utilizes AJAX to check the DB without refreshing the page
[Remote(action: "IsEmailAvailable", controller: "Validation")]
public string Email { get; set; }
[Required]
[Range(30000, 200000, ErrorMessage = "Salary must be realistic.")]
public decimal Salary { get; set; }
[Display(Name = "Department")]
public int DepartmentId { get; set; }
}
Controllers should focus entirely on HTTP logic (handling requests, validating model state, and returning UI views/redirects). They should delegate database operations to Repositories to enable Unit Testing.
[Authorize] // Secure the entire route
public class EmployeeController : Controller
{
private readonly IEmployeeRepository _repo;
// Dependency Injection guarantees testing mocks can be swapped here
public EmployeeController(IEmployeeRepository repo)
=> _repo = repo;
[HttpGet]
public async Task<IActionResult> Create()
{
// Load dropdown lists (SelectLists) for UI forms
ViewBag.Departments = await _repo.GetDepartmentsAsync();
return View(new EmployeeCreateViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken] // CSRF Protection enforced globally
public async Task<IActionResult> Create(EmployeeCreateViewModel model)
{
// 1. Immediately validate inputs
if (!ModelState.IsValid)
{
ViewBag.Departments = await _repo.GetDepartmentsAsync();
return View(model); // Bounce back with error states
}
// 2. Map ViewModel -> Domain Model
var entity = new Employee
{
FullName = model.FullName,
Email = model.Email,
Salary = model.Salary,
DepartmentId = model.DepartmentId,
DateOfJoining = DateTime.UtcNow
};
// 3. Delegate to Repository
await _repo.AddEmployeeAsync(entity);
// 4. Implement PRG Pattern using TempData
TempData["SuccessMessage"] = $"Employee {entity.FullName} onboarded securely.";
return RedirectToAction(nameof(Index));
}
}