Modern day websites need to handle requests from hundreds of thousands of visitors. Since most of the advanced websites are dynamic in nature, they have to interact with database servers and web services. Typical user requests involve sending an HTTP request to the web server, which after analyzing the request type, returns a webpage. When the request involves interaction with the database or a web service, response time increases – and when thousands of visitors are accessing the same resources, website performance can greatly decrease. Microsoft hasn’t overlooked these concerns and has therefore introduced asynchronous strategies in .NET framework 4.5, which address the aforementioned concerns. However, before reviewing C# asynchronous strategies, let’s answer the following important points:
Why Asynchronous Strategies have been introduced for Web Apps?
The following are some of the advantages of using asynchronous strategies in C# web applications.
- Ability to Handle More Requests – Asynchronous web applications are capable of handling more users as compared to traditional web based applications. Whenever a user requests a URL, the web application assigns it a thread from thread pool. In the case of thousands of visitors, all the threads in the thread pool get occupied and further requests are blocked. Asynchronous strategies help release the threads occupied by the request while the request is waiting for data to be fetched from database or web service. This allows websites to cater more requests.
- Parallel Execution of I/O Bound Methods – As aforementioned, websites interact with database servers and web services. Often times, responses are generated by integrating results from multiple calls to different database servers and web servers. These calls can be executed asynchronously.
- Improved Responsiveness – Asynchronous web applications provide an improved user experience and responsive interface to the visitors.
Implementing Asynchronous Strategies in C# Web Applications
C# based web applications can be made asynchronous via Async/Wait keywords introduced in .NET Framework 4.5. To understand how, Asynchronous methods are implemented in C#. Consider the following method which is NOT asynchronous.
public static int GetNumComments(BlogDB db)
int numComments = db.Comments.Count();
This is a method that fetches a total number of comments on all the posts on some imaginary blog. Here, BlogDB refers to the DbContext object of the entity framework. The method db.Comments.Count() can take quite a while to execute, since there can be hundreds of thousands of records. Let’s modify this method in to make it asynchronous:
private static async Task<int> GetNumCommentsAsync(BlogDB db)
int numComments =await db.Comments.CountAsync();
Now, if above method is carefully analyzed, three changes can be seen from the synchronous method, apart from the name which has been changed to GetNumCommentsAsync (for readability purposes). The keyword async has been inserted in the method definition after the static keyword. Every function that has to be called asynchronously is required to have this keyword in its definition.
The next change is in the return type, where keyword Task has been used. Remember, if the method you want to call synchronously returns void, its return type in its asynchronous counterpart would be Task, and if the return type of method is T, the return type of the corresponding asynchronous function would be Task<T>. Note that in the method described above, the synchronous version has return type int, whereas the asynchronous counterpart has a return type of Task<int>.
The third and final change that is required to be made for a function to be called asynchronously is the use of wait keyword. This is the place where the function waits for a task to complete asynchronously. For instance, in the GetNumCommentAsync method, the wait keyword has been used before calling the CountAsync method on the db.Comments entity collection (CountAsync is the counter part for the Count method on entity collection in EF6).When execution reaches this line, the current function will wait for the value returned by the db.Comments.CountAsync() method, while other functions will keep executing asynchronously, ultimately resulting in increased responsiveness and efficient performance.