CRUD Operation Using Asynchronous Method In ASP.NET MVC

7 minute read

Introduction
In .NET framework 4.5 asynchronous programming concept has been introduced. In this regard, .NET introduced two keyword async and await. It is much easier to implement than the multi-threading concept. The .NET Framework 4 introduced an asynchronous programming concept referred to as a Task and ASP.NET MVC 4 supports Task. In this article I will show you a simple CRUD operation using asynchronous programming by async, await and Task.

A simple overview on “async, await, Task” Keyword

async

  • The async modifier indicates that the method, lambda expression, or anonymous method will work asynchronously.
  • Method with async modifier also called async method.
  • An async method provides a convenient way to do potentially long-running work without blocking the caller’s thread.
  • The caller of an async method can resume its work without waiting for the async method to finish.
  • Typically, a method modified by the async keyword contains at least one await expression or statement.

await

  • Typically await keyword used to free a thread
  • The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes.
  • The asynchronous method in which await is used must be modified by the async keyword. Such a method, defined by using the async modifier, and usually containing one or more await expressions, is referred to as an async method.
  • The task to which the await operator is applied typically is the return value from a call to a method that implements.

Task

  • The main types are System.Threading.Tasks.Task
  • Represents an asynchronous operation that can be waited on and cancelled
  • System.Threading.Tasks.Task, which is a task that can return a value. MSDN References:

  • https://msdn.microsoft.com/en-us/library/hh156513(v=vs.110).aspx
  • https://msdn.microsoft.com/en-us/library/hh156528(v=vs.110).aspx
  • https://msdn.microsoft.com/en-us/library/system.threading.tasks(v=vs.110).aspx

Here I implement async modifier to a CRUD operation on Employee Object. Let’s start.

Tools and Technology used
I used following tools and technology to develop the project –

  • Visual Studio 2013
  • Visual C#
  • ASP.NET MVC 5
  • Entity Framework
  • Razor view engine

Step 1: Create an ASP.NET MVC 5 application using Visual Studio 2013.

  • Create an ASP.NET MVC 5 application name MVCAsync

Step 2: Configure connection string in web.config

<connectionStrings>
  <add name="DefaultConnection" connectionString="Data Source=localhost;Initial Catalog=EmployeeDB;User ID=sa; Password=sa@123" providerName="System.Data.SqlClient" />
</connectionStrings>

Step 3: Create a model in model folder - Employee

Employee.cs

public class Employee
 {
     public int Id { get; set; }
     public string Name { get; set; }
     public string NickName { get; set; }
     public string Designation { get; set; }
     public string Dept { get; set; }
 }

Step 4: Create a DbContext name EmployeeDBContext in Model folder.

public class EmployeeDBContext : DbContext
{
    public EmployeeDBContext()
        : base("DefaultConnection")
    {
    }
 
    public DbSet<Employee> Employees { get; set; }
}

Step 5: Create a controller name – EmployeeController.

  • Select template - MVC5 Controller with views, using entity framework
  • EmployeeController will create in Controller folder and related views will be created in Views/Employee folder.
  • At the time of creating controller - mark use async controller action.

Step 6: Employee Controller is given below.

  • A simple difference over normal method is –
    • used async keyword in Action Method.
    • Used Task instead of typical ActionResult
    • And used await keyword in any operation.
public class EmployeeController : Controller
 {
     private EmployeeDBContext db = new EmployeeDBContext();
 
     // GET: /Employee/
     public async Task<ActionResult> Index()
     {
         return View(await db.Employees.ToListAsync());
     }
 
     // GET: /Employee/Details/5
     public async Task<ActionResult> Details(int? id)
     {
         if (id == null)
         {
             return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
         }
         Employee employee = await db.Employees.FindAsync(id);
         if (employee == null)
         {
             return HttpNotFound();
         }
         return View(employee);
     }
 
     // GET: /Employee/Create
     public ActionResult Create()
     {
         return View();
     }
 
     // POST: /Employee/Create
     // To protect from overposting attacks, please 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<ActionResult> Create([Bind(Include="Id,Name,NickName,Designation,Dept")] Employee employee)
     {
         if (ModelState.IsValid)
         {
             db.Employees.Add(employee);
             await db.SaveChangesAsync();
             return RedirectToAction("Index");
         }
 
         return View(employee);
     }
 
     // GET: /Employee/Edit/5
     public async Task<ActionResult> Edit(int? id)
     {
         if (id == null)
         {
             return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
         }
         Employee employee = await db.Employees.FindAsync(id);
         if (employee == null)
         {
             return HttpNotFound();
         }
         return View(employee);
     }
 
     // POST: /Employee/Edit/5
     // To protect from overposting attacks, please 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<ActionResult> Edit([Bind(Include="Id,Name,NickName,Designation,Dept")] Employee employee)
     {
         if (ModelState.IsValid)
         {
             db.Entry(employee).State = EntityState.Modified;
             await db.SaveChangesAsync();
             return RedirectToAction("Index");
         }
         return View(employee);
     }
 
     // GET: /Employee/Delete/5
     public async Task<ActionResult> Delete(int? id)
     {
         if (id == null)
         {
             return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
         }
         Employee employee = await db.Employees.FindAsync(id);
         if (employee == null)
         {
             return HttpNotFound();
         }
         return View(employee);
     }
 
     // POST: /Employee/Delete/5
     [HttpPost, ActionName("Delete")]
     [ValidateAntiForgeryToken]
     public async Task<ActionResult> DeleteConfirmed(int id)
     {
         Employee employee = await db.Employees.FindAsync(id);
         db.Employees.Remove(employee);
         await db.SaveChangesAsync();
         return RedirectToAction("Index");
     }
 
     protected override void Dispose(bool disposing)
     {
         if (disposing)
         {
             db.Dispose();
         }
         base.Dispose(disposing);
     }
 }

Step 7: Views – After selecting and executing template views are automatically created. Here is the views for CRUD operation of Employee.

Create.cshtml

@model MVCAsync.Models.Employee
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Create</title>
</head>
<body>
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/jqueryval")
     
     
    @using (Html.BeginForm()) 
    {
        @Html.AntiForgeryToken()
         
        <div class="form-horizontal">
            <h4>Employee</h4>
            <hr />
            @Html.ValidationSummary(true)
     
            <div class="form-group">
                @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Name)
                    @Html.ValidationMessageFor(model => model.Name)
                </div>
            </div>
     
            <div class="form-group">
                @Html.LabelFor(model => model.NickName, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.NickName)
                    @Html.ValidationMessageFor(model => model.NickName)
                </div>
            </div>
     
            <div class="form-group">
                @Html.LabelFor(model => model.Designation, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Designation)
                    @Html.ValidationMessageFor(model => model.Designation)
                </div>
            </div>
     
            <div class="form-group">
                @Html.LabelFor(model => model.Dept, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Dept)
                    @Html.ValidationMessageFor(model => model.Dept)
                </div>
            </div>
     
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Create" class="btn btn-default" />
                </div>
            </div>
        </div>
    }
     
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>
</body>
</html>

Delete.cshtml

@model MVCAsync.Models.Employee
 
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Delete</title>
</head>
<body>
    <h3>Are you sure you want to delete this?</h3>
    <div>
        <h4>Employee</h4>
        <hr />
        <dl class="dl-horizontal">
            <dt>
                @Html.DisplayNameFor(model => model.Name)
            </dt>
     
            <dd>
                @Html.DisplayFor(model => model.Name)
            </dd>
     
            <dt>
                @Html.DisplayNameFor(model => model.NickName)
            </dt>
     
            <dd>
                @Html.DisplayFor(model => model.NickName)
            </dd>
     
            <dt>
                @Html.DisplayNameFor(model => model.Designation)
            </dt>
     
            <dd>
                @Html.DisplayFor(model => model.Designation)
            </dd>
     
            <dt>
                @Html.DisplayNameFor(model => model.Dept)
            </dt>
     
            <dd>
                @Html.DisplayFor(model => model.Dept)
            </dd>
     
        </dl>
     
        @using (Html.BeginForm()) {
            @Html.AntiForgeryToken()
     
            <div class="form-actions no-color">
                <input type="submit" value="Delete" class="btn btn-default" /> |
                @Html.ActionLink("Back to List", "Index")
            </div>
        }
    </div>
</body>
</html>

Details.cshtml

@model MVCAsync.Models.Employee
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Details</title>
</head>
<body>
    <div>
        <h4>Employee</h4>
        <hr />
        <dl class="dl-horizontal">
            <dt>
                @Html.DisplayNameFor(model => model.Name)
            </dt>
     
            <dd>
                @Html.DisplayFor(model => model.Name)
            </dd>
     
            <dt>
                @Html.DisplayNameFor(model => model.NickName)
            </dt>
     
            <dd>
                @Html.DisplayFor(model => model.NickName)
            </dd>
     
            <dt>
                @Html.DisplayNameFor(model => model.Designation)
            </dt>
     
            <dd>
                @Html.DisplayFor(model => model.Designation)
            </dd>
     
            <dt>
                @Html.DisplayNameFor(model => model.Dept)
            </dt>
     
            <dd>
                @Html.DisplayFor(model => model.Dept)
            </dd>
     
        </dl>
    </div>
    <p>
        @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
        @Html.ActionLink("Back to List", "Index")
    </p>
</body>
</html>

Edit.cshtml

@model MVCAsync.Models.Employee
 
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Edit</title>
</head>
<body>
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/jqueryval")
     
     
    @using (Html.BeginForm())
    {
        @Html.AntiForgeryToken()
         
        <div class="form-horizontal">
            <h4>Employee</h4>
            <hr />
            @Html.ValidationSummary(true)
            @Html.HiddenFor(model => model.Id)
     
            <div class="form-group">
                @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Name)
                    @Html.ValidationMessageFor(model => model.Name)
                </div>
            </div>
     
            <div class="form-group">
                @Html.LabelFor(model => model.NickName, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.NickName)
                    @Html.ValidationMessageFor(model => model.NickName)
                </div>
            </div>
     
            <div class="form-group">
                @Html.LabelFor(model => model.Designation, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Designation)
                    @Html.ValidationMessageFor(model => model.Designation)
                </div>
            </div>
     
            <div class="form-group">
                @Html.LabelFor(model => model.Dept, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Dept)
                    @Html.ValidationMessageFor(model => model.Dept)
                </div>
            </div>
     
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Save" class="btn btn-default" />
                </div>
            </div>
        </div>
    }
     
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>
</body>
</html>

Index.cshtml

@model IEnumerable<MVCAsync.Models.Employee>
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <p>
        @Html.ActionLink("Create New", "Create")
    </p>
    <table class="table">
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Name)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.NickName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Designation)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Dept)
            </th>
            <th></th>
        </tr>
     
    @foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.NickName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Designation)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Dept)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
                @Html.ActionLink("Details", "Details", new { id=item.Id }) |
                @Html.ActionLink("Delete", "Delete", new { id=item.Id })
            </td>
        </tr>
    }
     
    </table>
</body>
</html>

Step 8: Add a link to _Layout page to access Employee information in Views/Shared

<ul class="nav navbar-nav">
    <li>@Html.ActionLink("Home", "Index", "Home")</li>
    <li>@Html.ActionLink("About", "About", "Home")</li>
    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
    <li>@Html.ActionLink("Employee", "Index", "Employee")</li>
</ul>

Step 9: Run the following command in package manager console one after another

PM> Enable-Migrations -ContextTypeName EmployeeDBContext
PM> Add-Migration created
PM> Update-Database –Verbose

Now run application and apply CRUD operation on it. It’s simple!!