Build a CRUD application using asp.net core

9 minute read

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.

Source Code