So far we have used the synchronous programming model to read, write and update data. In this article, we will see how to implement the asynchronous programming model.
A web server has a limited number of threads available, and in high load situations, all of the available threads might be in use. When that happens, the server can't process new requests until the threads are freed up.
Let's create a BookController
the same way we created an AuthorController
, except this time we will select the Use async controller actions check box.
If you open the BookController
and look at the Index
action, you will see some changes as compared to synchronous code.
public async Task<ActionResult> Index()
{
var books = db.Books.Include(b => b.Author);
return View(await books.ToListAsync());
}
async
keyword tells the compiler to generate callbacks for parts of the method body and to automatically create the Task<ActionResult>
object that is returned.ActionResult
to Task<ActionResult>
. The Task<T>
type represents ongoing work with a result of type T
.await
keyword was applied to the web service call, when the compiler sees this keyword, behind the scenes it splits the method into two parts.
In Index
method, you can see that books.ToList
statement modified but not the var books = db.Books
statement.
var books = db.Books
statement sets up a query but the query is not executed until the ToList
method is called.ToList
method is executed asynchronously.In the Details
method and the HttpGet
Edit
and Delete
methods, the Find
method causes a query to be sent to the database, so that's the method that gets executed asynchronously.
public async Task<ActionResult> Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Book book = await db.Books.FindAsync(id);
if (book == null)
{
return HttpNotFound();
}
return View(book);
}
In the Create
, HttpPost
Edit
, and DeleteConfirmed
methods, it is the SaveChanges
method call that causes a command to be executed, not statements such as db.Books.Add(book)
which only cause entities in memory to be modified.
public async Task<ActionResult> Create([Bind(Include = "BookId,Title,AuthorId")] Book book)
{
if (ModelState.IsValid)
{
db.Books.Add(book);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.AuthorId = new SelectList(db.Authors, "AuthorId", "FirstName", book.AuthorId);
return View(book);
}
Let's replace the following code in Views\Book\Index.cshtml file by changing the title to Books, moves the Author name to the right, and provides the full name of the author.
@model IEnumerable<MvcWithEF6Demo.Models.Book>
@{
ViewBag.Title = "Books";
}
<h2>Books</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
Author
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Author.FullName)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.BookId }) |
@Html.ActionLink("Details", "Details", new { id = item.BookId }) |
@Html.ActionLink("Delete", "Delete", new { id = item.BookId })
</td>
</tr>
}
</table>
In the Create
, Delete
, Details
, and Edit
views, we need to change the caption for the AuthorId field to Author.
In Create
and Edit
views you will see the caption line as shown below.
@Html.LabelFor(model => model.AuthorId, "AuthorId", htmlAttributes: new { @class = "control-label col-md-2" })
Replace the above line with the following line.
<label class="control-label col-md-2" for="AuthorId">Author</label>
Now let's update the Details
view by using the author FullName instead of FirstName and also move the full name field below book title as shown below.
@model MvcWithEF6Demo.Models.Book
@{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<div>
<h4>Book</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd>
@Html.DisplayFor(model => model.Title)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Author.FullName)
</dt>
<dd>
@Html.DisplayFor(model => model.Author.FullName)
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.BookId }) |
@Html.ActionLink("Back to List", "Index")
</p>
Repeat the same changes in Delete
view as well.
@model MvcWithEF6Demo.Models.Book
@{
ViewBag.Title = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Book</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd>
@Html.DisplayFor(model => model.Title)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Author.FullName)
</dt>
<dd>
@Html.DisplayFor(model => model.Author.FullName)
</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>
Now run your application and click on Books tab.