
June 17, 2026 09:01 by
Peter
Systems for managing human resources (HRMS) are crucial for contemporary businesses. They automate hiring, payroll, personnel records, and attendance. The open-source HRM project shows how to use SQL Server, Entity Framework Core, and ASP.NET Core MVC to create a comprehensive HRMS.

Step 1: Environment Setup
- Install Visual Studio 2022 with ASP.NET workload.
- Install SQL Server and SSMS.
- Clone the repository
- Open the solution in Visual Studio.
Step 2: Database Configuration
- Update appsettings.json with your SQL Server connection string.
- Run EF Core migrations:
Update-Database
-
This creates tables like AspNetUsers, AspNetRoles, Companies, Departments, Designations.
Step 3: Authentication & Roles
- The project uses ASP.NET Identity.
- Roles: Admin, HR, Manager, Employee.
- Login page: /Identity/Account/Login.
- Debugging tip: Place a breakpoint in Login.cshtml.cs → OnPostAsync() to inspect validation.
Step 4: Admin Module
- Dashboard → Overview of employees, departments, payroll.
- Companies → CRUD for company records.
- Departments → CRUD linked to companies.
- Designations → CRUD linked to companies.
- Role Management → Assign roles to users.
Step 5: HR Module
- Employee Management → Add, edit, delete employees.
- Attendance → Mark daily attendance.
- Leave Requests → Approve/reject employee leave.
- Recruitment → Generate offer letters, onboarding workflows.
Step 6: Manager Module
- Team Dashboard → View team members and performance.
- Approve Leave → Approve/reject leave requests.
- Reports → Attendance and performance reports.
Step 7: Employee Module
- Profile → View/update personal details.
- Attendance → Mark attendance.
- Leave Application → Submit leave requests.
- Salary Slip → View/download salary slips.
- Offer Letter → View recruitment documents.
Step 8: Payroll & Reports
- Payroll Management → Salary calculation, deductions, bonuses.
- Salary Slips → Generate and export slips.
- Reports → Attendance, payroll, performance analytics.
Step 9: Deployment
- Publish to IIS or Azure.
- Configure connection strings for production.
- Secure sensitive data with Azure Key Vault or environment variables.
Admin Module – Companies, Departments, Designations
Companies Page
Step 1: Model
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public int LocId { get; set; }
public string Address { get; set; }
public Location Location { get; set; }
public ICollection<Department> Departments { get; set; }
}
Step 2: Controller
public class CompaniesController : Controller
{
private readonly ApplicationDbContext _context;
public CompaniesController(ApplicationDbContext context) => _context = context;
public async Task<IActionResult> Index()
{
var companies = await _context.Companies.Include(c => c.Location).ToListAsync();
return View(companies);
}
public IActionResult Create() => View();
[HttpPost]
public async Task<IActionResult> Create(Company company)
{
if (ModelState.IsValid)
{
_context.Add(company);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(company);
}
}
Step 3: View
@model IEnumerable<Company>
<h2>Companies</h2>
<table class="table">
<tr><th>Name</th><th>Location</th><th>Address</th></tr>
@foreach (var c in Model)
{
<tr>
<td>@c.Name</td>
<td>@c.Location.Name</td>
<td>@c.Address</td>
</tr>
}
</table>

Departments Page
Step 1: Model
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public int CompanyId { get; set; }
public Company Company { get; set; }
}
Step 2: Controller
public class DepartmentsController : Controller
{
private readonly ApplicationDbContext _context;
public DepartmentsController(ApplicationDbContext context) => _context = context;
public async Task<IActionResult> Index()
{
var departments = await _context.Departments.Include(d => d.Company).ToListAsync();
return View(departments);
}
public IActionResult Create() => View();
[HttpPost]
public async Task<IActionResult> Create(Department department)
{
if (ModelState.IsValid)
{
_context.Add(department);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(department);
}
}
Step 3: View
@model IEnumerable<Department>
<h2>Departments</h2>
<table class="table">
<tr><th>Name</th><th>Company</th></tr>
@foreach (var d in Model)
{
<tr>
<td>@d.Name</td>
<td>@d.Company.Name</td>
</tr>
}
</table>

Designations Page
Step 1: Model
public class Designation
{
public int Id { get; set; }
public string Name { get; set; }
public int CompanyId { get; set; }
public Company Company { get; set; }
}
Step 2: Controller
public class DesignationsController : Controller
{
private readonly ApplicationDbContext _context;
public DesignationsController(ApplicationDbContext context) => _context = context;
public async Task<IActionResult> Index()
{
var designations = await _context.Designations.Include(d => d.Company).ToListAsync();
return View(designations);
}
public IActionResult Create() => View();
[HttpPost]
public async Task<IActionResult> Create(Designation designation)
{
if (ModelState.IsValid)
{
_context.Add(designation);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(designation);
}
}
Step 3: View
@model IEnumerable<Designation>
<h2>Designations</h2>
<table class="table">
<tr><th>Name</th><th>Company</th></tr>
@foreach (var d in Model)
{
<tr>
<td>@d.Name</td>
<td>@d.Company.Name</td>
</tr>
}
</table>

Employee Model
Define the employee entity with relationships to company, department, and designation:
public class Employee
{
public int Id { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public int CompanyId { get; set; }
public Company Company { get; set; }
public int DepartmentId { get; set; }
public Department Department { get; set; }
public int DesignationId { get; set; }
public Designation Designation { get; set; }
public DateTime JoiningDate { get; set; }
}
Employee Controller
Create an MVC controller to handle CRUD operations:
public class EmployeesController : Controller
{
private readonly ApplicationDbContext _context;
public EmployeesController(ApplicationDbContext context) => _context = context;
// List all employees
public async Task<IActionResult> Index()
{
var employees = await _context.Employees
.Include(e => e.Company)
.Include(e => e.Department)
.Include(e => e.Designation)
.ToListAsync();
return View(employees);
}
// Create employee
public IActionResult Create()
{
ViewBag.Companies = new SelectList(_context.Companies, "Id", "Name");
ViewBag.Departments = new SelectList(_context.Departments, "Id", "Name");
ViewBag.Designations = new SelectList(_context.Designations, "Id", "Name");
return View();
}
[HttpPost]
public async Task<IActionResult> Create(Employee employee)
{
if (ModelState.IsValid)
{
_context.Add(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(employee);
}
// Edit employee
public async Task<IActionResult> Edit(int id)
{
var employee = await _context.Employees.FindAsync(id);
if (employee == null) return NotFound();
ViewBag.Companies = new SelectList(_context.Companies, "Id", "Name", employee.CompanyId);
ViewBag.Departments = new SelectList(_context.Departments, "Id", "Name", employee.DepartmentId);
ViewBag.Designations = new SelectList(_context.Designations, "Id", "Name", employee.DesignationId);
return View(employee);
}
[HttpPost]
public async Task<IActionResult> Edit(Employee employee)
{
if (ModelState.IsValid)
{
_context.Update(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(employee);
}
// Delete employee
public async Task<IActionResult> Delete(int id)
{
var employee = await _context.Employees.FindAsync(id);
if (employee == null) return NotFound();
_context.Employees.Remove(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
}
Employee Views
Index.cshtml
@model IEnumerable<Employee>
<h2>Employees</h2>
<a asp-action="Create" class="btn btn-primary">Add Employee</a>
<table class="table">
<tr>
<th>Name</th><th>Email</th><th>Phone</th>
<th>Company</th><th>Department</th><th>Designation</th><th>Joining Date</th><th>Actions</th>
</tr>
@foreach (var e in Model)
{
<tr>
<td>@e.FullName</td>
<td>@e.Email</td>
<td>@e.Phone</td>
<td>@e.Company.Name</td>
<td>@e.Department.Name</td>
<td>@e.Designation.Name</td>
<td>@e.JoiningDate.ToShortDateString()</td>
<td>
<a asp-action="Edit" asp-route-id="@e.Id">Edit</a> |
<a asp-action="Delete" asp-route-id="@e.Id">Delete</a>
</td>
</tr>
}
</table>
Create.cshtml
@model Employee
<h2>Add Employee</h2>
<form asp-action="Create">
<div class="form-group">
<label>Name</label>
<input asp-for="FullName" class="form-control" />
</div>
<div class="form-group">
<label>Email</label>
<input asp-for="Email" class="form-control" />
</div>
<div class="form-group">
<label>Phone</label>
<input asp-for="Phone" class="form-control" />
</div>
<div class="form-group">
<label>Company</label>
<select asp-for="CompanyId" asp-items="ViewBag.Companies" class="form-control"></select>
</div>
<div class="form-group">
<label>Department</label>
<select asp-for="DepartmentId" asp-items="ViewBag.Departments" class="form-control"></select>
</div>
<div class="form-group">
<label>Designation</label>
<select asp-for="DesignationId" asp-items="ViewBag.Designations" class="form-control"></select>
</div>
<div class="form-group">
<label>Joining Date</label>
<input asp-for="JoiningDate" type="date" class="form-control" />
</div>
<button type="submit" class="btn btn-success">Save</button>
</form>
