Async in Web API, Entity Framework 6 and ASP.NET Web Forms vNext

Posted by: Suprotim Agarwal , on 8/16/2013, in Category ASP.NET
Views: 30842
Abstract: A quick look at how asynchronous support is permeating though the entire Web Stack in ASP.NET vNext and that includes WebForms too!

.NET Framework 4.5 as we all know has introduced the new async and await keywords that go a long way in making Asynchronous easier. However async APIs are ‘viral’ in nature, meaning all calls up and down the call stack need to be Async. This ‘was’ a problem initially but as the APIs built on top of the Framework mature, the entire call stack is developing Async counterparts making Async usage easier. Today we’ll see how we can use the latest Async APIs all across the ASP.NET stack.

The ASP.NET Web API Sample

In today’s example, we’ll build a Web API Service that fetches data from database. We will use EF 6 beta and see all it’s Async goodness, and a WinForms client application that will create a dashboard that fetches data using the Web API services.

 

With the Basic premise out of the way, let’s get cracking. Note that we are using Visual Studio 2013 Preview.

Step 1: We start off by creating an ASP.NET Project and select the WebForms client. The reason I am selecting WebForms is to show off the Async related enhancements that are coming in Web Forms.

new-webforms-project

Now I could have selected Web API here itself but I wanted to keep the service separate and treat this application as a client or service consumer. Hence the project is named ClientApp.

Step 2: Next we add a new Project, name it Service and this time select the Web API template.

new-web-api-project

Step 3: Once the project is setup, (in the Service project) we add reference to EntityFramework 6 (currently in beta). This is because EF6 introduces Async for all calls that actually return data like Find, First, ToList, ToArray and so on.

To install EF we use the following command in the Package Manager Console.

PM> install-package EntityFramework –pre

Step 4: Next we add an Employee entity in the Models folder.

public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Email {get; set; }
}

Build the solution.

Step 5: We now scaffold an ApiController to manipulate the Employee entity. Right click on the Controller folder and select the “Scaffold…” menu item. This will bring up the following dialog

add-ef-scaffolding

Here we select the option to scaffold Web API 2 controller with EF. On clicking ‘Add’, we get the following dialog to select the Controller Name, Model class and the Data Context. Since this is our first context, we’ll have to provide a new Name. Click on ‘Add’ to complete the scaffolding process.

add-ef-scaffolding-next-step

If we take a peek at the generated Controller, we’ll see that it’s a Non-async action method using the non-async AsEnumerable() method to retrieve all the Employees using the EF DB Context.

get-employee-synchronous

Step 6: Back to the ClientApp project, we open up the Default.aspx and drop a GridView control on it. We name it Employees and as you can see below, I’ve removed the default markup that comes in the page.

default-aspx-gridview

Step 7: Before we continue with the databinding, we add an Employee entity in the ClientApp project as well. It will serve as our client ‘proxy’. In the Code behind file Default.aspx.cs we add the following code to call the Web API service, then convert the JSON returned into list of Employee objects, which are then bound to the DataGrid.

page-load-sync

All set, run the application! Initially you’ll see nothing because there is no data in the DB. I sneaked behind the scenes and added three records in the table:

data-added-to-employee-table

Now if you run the application, the Default.aspx should looks like this:

default-aspx-output

Going Async

With the synchronous implementation in place let’s make changes to go Async. We start with the Page_Load event in Default.aspx. Usually we add the async keyword to the method and then call the async version of the API (DownloadStringAsync in this case). However for the ASP.NET Page life cycle, this is not an ideal solution because adding an async makes the pipeline wait for all await calls to complete. This can potentially slow down the page cycle.

To work around this, we now have a RegisterAsyncTask helper method that takes an async function definition and hands over a Task to ASP.NET which is typically executed before the Page Pre-render. The syntax to use RegisterAsyncTask is as follows:

page-load-async

So now we have converted our client to use the API asynchronously. If we run the application now, we’ll get a YSOD!

register-async-ysod

Oops what happened? Well, we ‘forgot’ on more attribute that we have to set in the Markup (as cryptically hinted above). Open the Default.aspx and add an attribute Async=”true” to the <%@ Page … >

page-async-attribute

Now if we run the app it will run successfully. But we are not using EF’s new async features yet. Let’s do that next.

Async Entity Framework Calls

Let’s switch back to the Service project and in the DataController.cs, we can see the ToListAsync, ToArrayAsync, ToDictionaryAsync methods available in the Intellisense popup:

ef-async-calls

We update the GetEmployee method to return a Task of List<Employee> asynchronously. We add the await keyword to the ToListAsync<Employee> method to complete the ‘async-fication’ of the method.

get-employee-async

That’s about it. We are done converting our Synchronous app into an asynchronous one. Run the app and you’ll see the same output.

Key Takeaways

Before we wrap up let’s recap and consider some of the gains of async that we haven’t quantified today (we’ll do that in a separate article).

- ASP.NET vNext’s support of async enables you to use Async APIs seamlessly.

- You don’t have to do anything special to create and use Asynchronous Web API calls.

- ASP.NET takes care of thread affinity when doing Async calls. Note in the Default.aspx.cs’ Page_Load event we are calling the Service, getting data asynchronously, then binding to the DataGrid without any threading issues even though it’s possible that the data request was on thread 1 and when we awaited that call, that physical thread was assigned to some other task. When our data returned we could have been handed over to Thread 2 to complete the task. ASP.NET took care of resource marshaling.

- The one thing we didn’t measure quantitatively is performance, however, async is all about scaling and hence raw speed increases are not seen unless a lot of chained synchronous calls are parallelized.

Conclusion

With those takeaways, we conclude the today’s introduction to Async features in ASP.NET vNext and EF 6. Things are getting progressively async in the entire stack and that can only be a good thing for demanding apps that we are going to build in the future (and gives us a good reason to upgrade our current apps as well)!

Download the entire source code of this article (Github)

Give a +1 to this article if you think it was well written. Thanks!
Recommended Articles
Suprotim Agarwal, ASP.NET Architecture MVP, MCSD, MCAD, MCDBA, MCSE, is the CEO of A2Z Knowledge Visuals Pvt. He primarily works as an Architect Consultant and provides consultancy on how to design and develop .NET centric database solutions.

Suprotim is the founder and primary contributor to DotNetCurry, DNC .NET Magazine, SQLServerCurry and DevCurry. He has also written an EBook 51 Recipes using jQuery with ASP.NET Controls. and is authoring another one at The Absolutely Awesome jQuery CookBook.

Follow him on twitter @suprotimagarwal


Page copy protected against web site content infringement by Copyscape


User Feedback
Comment posted by Julien on Sunday, September 8, 2013 4:59 AM
Hey, thanks for this article.

I just wanted to add a small precision: the fact that you implement your service API with async tasks is independent from the fact that you consume this API asynchronously. You could very well synchronously consume an async API or asynchronously consume a synchronous API, because the HTTP layer between your API and your application will isolate them anyway.
Comment posted by zbrong on Sunday, May 11, 2014 8:49 PM
very good!

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel