Build a CRUD application using asp.net core
Application overview
In this application, I will show how to build a CRUD application using asp.net mvc core. Let’s have a look on the implementation of the project.
Tools and Technology used The following tools and technologies has been used for this application
- Visual Studio 2019
- Visual C#
- ASP.NET Core MVC
- Entity Framework
- Razor view engine
Step1: Select ASP.NET Core Web Application
Select File->New->Project->ASP.NET Core Web Application
Step2: Choose project and solution name
Type project name as “HRM” and also solution name as “HRM”
Step 3: Select project template
- Select project template as Web Application (Model-View-Controller)
- Change authentication to Individual User Authentication (Optional)
- Click create button
Step 4: Modify appsettings.json
Change connection string as follows. Since, I am using localdb.
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=HRMDB;Trusted_Connection=True;MultipleActiveResultSets=true"
}
Step 5: Add following model class in Models folder
Dept.cs
public class Dept
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key, Column(Order = 0)]
public int Id { get; set; }
[Display(Name = "Dept. Name")]
[StringLength(150)]
public string Name { get; set; }
public List<Employee> Employees { get; set; }
}
Employee.cs
public class Employee
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key, Column(Order = 0)]
public int Id { get; set; }
[Display(Name = "Full Name")]
[StringLength(200)]
public string FullName { get; set; }
[Display(Name = "Father's Name")]
[StringLength(200)]
public string FathersName { get; set; }
[Display(Name = "Mother's Name")]
[StringLength(200)]
public String MothersName { get; set; }
[Display(Name = "Dept")]
public int DeptId { get; set; }
[StringLength(250)]
public string Designation { get; set; }
[ForeignKey("DeptId")]
public virtual Dept Dept { get; set; }
}
Step 6: Create Controller and Views for Dept
- Add DeptsController in Controllers folder
- Choose template MVC controller with views, using Entity Framework
- Select Model Class as Dept
- Select ApplicationDbContext as DbContext class
- DeptsController and corresponding views will be created automatically as follows
DeptsController
public class DeptsController : Controller
{
private readonly ApplicationDbContext _context;
public DeptsController(ApplicationDbContext context)
{
_context = context;
}
// GET: Depts
public async Task<IActionResult> Index()
{
return View(await _context.Dept.ToListAsync());
}
// GET: Depts/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var dept = await _context.Dept
.FirstOrDefaultAsync(m => m.Id == id);
if (dept == null)
{
return NotFound();
}
return View(dept);
}
// GET: Depts/Create
public IActionResult Create()
{
return View();
}
// POST: Depts/Create
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name")] Dept dept)
{
if (ModelState.IsValid)
{
_context.Add(dept);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(dept);
}
// GET: Depts/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var dept = await _context.Dept.FindAsync(id);
if (dept == null)
{
return NotFound();
}
return View(dept);
}
// POST: Depts/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Name")] Dept dept)
{
if (id != dept.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(dept);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!DeptExists(dept.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(dept);
}
// GET: Depts/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var dept = await _context.Dept
.FirstOrDefaultAsync(m => m.Id == id);
if (dept == null)
{
return NotFound();
}
return View(dept);
}
// POST: Depts/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var dept = await _context.Dept.FindAsync(id);
_context.Dept.Remove(dept);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool DeptExists(int id)
{
return _context.Dept.Any(e => e.Id == id);
}
}
- Following views will be created automatically in Views->Depts folder
Index.cshtml
@model IEnumerable<HRM.Models.Dept>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Create.cshtml
@model HRM.Models.Dept
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Dept</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Delete.cshtml
@model HRM.Models.Dept
@{
ViewData["Title"] = "Delete";
}
<h1>Delete</h1>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Dept</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Name)
</dd>
</dl>
<form asp-action="Delete">
<input type="hidden" asp-for="Id" />
<input type="submit" value="Delete" class="btn btn-danger" /> |
<a asp-action="Index">Back to List</a>
</form>
</div>
Details.cshtml
@model HRM.Models.Dept
@{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>Dept</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Name)
</dd>
</dl>
</div>
<div>
<a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
<a asp-action="Index">Back to List</a>
</div>
Edit.cshtml
@model HRM.Models.Dept
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Dept</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Step 7: Create Controller and Views for Employee
- Add EmployeesController in Controllers folder
- Choose template MVC controller with views, using Entity Framework
- Select Model Class as Employee
- Select ApplicationDbContext as DbContext class
- EmployeesController and corresponding views will be created automatically as follows
EmployeesController
public class EmployeesController : Controller
{
private readonly ApplicationDbContext _context;
public EmployeesController(ApplicationDbContext context)
{
_context = context;
}
// GET: Employees
public async Task<IActionResult> Index()
{
var applicationDbContext = _context.Employee.Include(e => e.Dept);
return View(await applicationDbContext.ToListAsync());
}
// GET: Employees/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var employee = await _context.Employee
.Include(e => e.Dept)
.FirstOrDefaultAsync(m => m.Id == id);
if (employee == null)
{
return NotFound();
}
return View(employee);
}
// GET: Employees/Create
public IActionResult Create()
{
ViewData["DeptId"] = new SelectList(_context.Dept, "Id", "Name");
return View();
}
// POST: Employees/Create
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,FullName,FathersName,MothersName,DeptId,Designation")] Employee employee)
{
if (ModelState.IsValid)
{
_context.Add(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["DeptId"] = new SelectList(_context.Dept, "Id", "Name", employee.DeptId);
return View(employee);
}
// GET: Employees/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var employee = await _context.Employee.FindAsync(id);
if (employee == null)
{
return NotFound();
}
ViewData["DeptId"] = new SelectList(_context.Dept, "Id", "Name", employee.DeptId);
return View(employee);
}
// POST: Employees/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,FullName,FathersName,MothersName,DeptId,Designation")] Employee employee)
{
if (id != employee.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(employee);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!EmployeeExists(employee.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
ViewData["DeptId"] = new SelectList(_context.Dept, "Id", "Name", employee.DeptId);
return View(employee);
}
// GET: Employees/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var employee = await _context.Employee
.Include(e => e.Dept)
.FirstOrDefaultAsync(m => m.Id == id);
if (employee == null)
{
return NotFound();
}
return View(employee);
}
// POST: Employees/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var employee = await _context.Employee.FindAsync(id);
_context.Employee.Remove(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool EmployeeExists(int id)
{
return _context.Employee.Any(e => e.Id == id);
}
}
- Following views will be created automatically in Views->Employees folder
Index.cshtml
@model IEnumerable<HRM.Models.Employee>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.FullName)
</th>
<th>
@Html.DisplayNameFor(model => model.FathersName)
</th>
<th>
@Html.DisplayNameFor(model => model.MothersName)
</th>
<th>
@Html.DisplayNameFor(model => model.Designation)
</th>
<th>
@Html.DisplayNameFor(model => model.Dept)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.FullName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FathersName)
</td>
<td>
@Html.DisplayFor(modelItem => item.MothersName)
</td>
<td>
@Html.DisplayFor(modelItem => item.Designation)
</td>
<td>
@Html.DisplayFor(modelItem => item.Dept.Name)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Create.cshtml
@model HRM.Models.Employee
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Employee</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="FullName" class="control-label"></label>
<input asp-for="FullName" class="form-control" />
<span asp-validation-for="FullName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FathersName" class="control-label"></label>
<input asp-for="FathersName" class="form-control" />
<span asp-validation-for="FathersName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MothersName" class="control-label"></label>
<input asp-for="MothersName" class="form-control" />
<span asp-validation-for="MothersName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DeptId" class="control-label"></label>
<select asp-for="DeptId" class ="form-control" asp-items="ViewBag.DeptId"></select>
</div>
<div class="form-group">
<label asp-for="Designation" class="control-label"></label>
<input asp-for="Designation" class="form-control" />
<span asp-validation-for="Designation" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Delete.cshtml
@model HRM.Models.Employee
@{
ViewData["Title"] = "Delete";
}
<h1>Delete</h1>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Employee</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.FullName)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.FullName)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.FathersName)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.FathersName)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.MothersName)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.MothersName)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Designation)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Designation)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Dept)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Dept.Id)
</dd class>
</dl>
<form asp-action="Delete">
<input type="hidden" asp-for="Id" />
<input type="submit" value="Delete" class="btn btn-danger" /> |
<a asp-action="Index">Back to List</a>
</form>
</div>
Details.cshtml
@model HRM.Models.Employee
@{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>Employee</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.FullName)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.FullName)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.FathersName)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.FathersName)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.MothersName)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.MothersName)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Designation)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Designation)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Dept)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Dept.Name)
</dd>
</dl>
</div>
<div>
<a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
<a asp-action="Index">Back to List</a>
</div>
Edit.cshtml
@model HRM.Models.Employee
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Employee</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="FullName" class="control-label"></label>
<input asp-for="FullName" class="form-control" />
<span asp-validation-for="FullName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FathersName" class="control-label"></label>
<input asp-for="FathersName" class="form-control" />
<span asp-validation-for="FathersName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MothersName" class="control-label"></label>
<input asp-for="MothersName" class="form-control" />
<span asp-validation-for="MothersName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DeptId" class="control-label"></label>
<select asp-for="DeptId" class="form-control" asp-items="ViewBag.DeptId"></select>
<span asp-validation-for="DeptId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Designation" class="control-label"></label>
<input asp-for="Designation" class="form-control" />
<span asp-validation-for="Designation" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
- Modify the navbar of _Layout.cshtml in Views->Shared folder as follows
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<partial name="_LoginPartial" />
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Depts" asp-action="Index">Depts</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Employees" asp-action="Index">Employees</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
</div>
Step 8: Run migration command in package manager console
Now the application is ready to run.