Introduction
The Model View Controller Design pattern can be used to isolate the application’s business logic from its user interface components. This promotes loose coupling and lesser cohesion amongst the components and as a result, the components of the application become easier to test and maintain. This article is an attempt to illustrate how you can implement asynchronous operations in your ASP.NET MVC applications.
Pre-requisites
To use the code examples illustrated in this article, you should have the following installed in your system:
- Microsoft Visual Studio 2010 RC or higher
- ASP.NET MVC Framework 2.0 or higher
What is the Model View Controller Design Pattern?
The Wikipedia states: “Model-View-Controller (MVC) is a software architecture, currently considered an architectural pattern used in software engineering. The pattern isolates “domain logic” (the application logic for the user) from input and presentation (GUI), permitting independent development, testing and maintenance of each.” Reference: http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
Applications that have a mix of data access, business logic and presentation layer code are difficult to test and maintain because of the interdependencies amongst the components. A change in any of said components would incur a change in the components that depend on the component that has changed. The MVC Design Pattern solves these problems by reducing the cohesion amongst the components in an application. It does this by decoupling the data access, business logic, and data presentation and user interaction components resulting in loosely coupled and easily testable components.
A lot of frameworks have been designed based on this design pattern. These include: ASP.NET MVC Framework, Ruby on Rails, Merb, Struts, Spring, and Django.
The architectural components of the MVC Design include:
- Model – this comprises the application’s business logic and data access components
- View – this includes the application’s user interface components
- Controller – this layer is responsible for handling the interaction amongst the other two components, handling user interactions, changing model state and invalidating the view based on the model’s data.
A Quick Tour of the ASP.NET MVC Framework
ASP.NET MVC Framework is one of the most exciting advancements in Microsoft Web Technologies since ASP.NET came into the market way back in 2002. The ASP.NET MVC Framework is based on the proven, tested and popular Model View Controller (commonly known as MVC) design pattern.
The ASP.NET MVC Framework provides support for the following features:
- Support for a Test Driven Design model
- Support for Dependency Injection and IOC containers
- Support for clean URLs and navigation support
- Support for REST-based design
- Pluggable, extensible, and maintainable
- Support for all existing ASP.NET features that includes, authentication, authorization, membership and role management, state management, etc
The ASP.NET MVC Framework provides you a paradigm shift from the way web applications are designed in ASP.NET. You can use this framework to design and implement web applications in a more structured way, make them testable, maintainable and extendable and using less code.
What are Synchronous and Asynchronous Operations?
What are synchronous and asynchronous operations and when should you decide to have methods that make synchronous or asynchronous calls? Applications are CPU bound, I/O bound or a mix of both. The decision of opting for synchronous or asynchronous operations depends on to what extent the operation is CPU or I/O intensive. You can use synchronous methods or operations when the operations are short-running, are CPU bound operations and their implementation needs to be simple. There is no point in using asynchronous methods for performing CPU bound operations as it would result in more overhead.
You can use asynchronous operations or methods when the operations are long-running, are more I/O bound and also when parallelism is preferred over simplicity of code to eliminate blocking operations. Most importantly, you can use asynchronous operations to allow the user to cancel the operation if need be. Note that intensive I/O operations can result in blocking operations if they are called synchronously as I/O operations take longer time to complete. Typical examples of intensive time consuming I/O operations include, database operations, reading and writing to disk files, calling external web services, etc.
What happens when an asynchronous operation is invoked? When an asynchronous action method is invoked, the IIS (if you are using IIS as your web server) web server fetches a worker thread from the thread pool and uses this thread to handle the incoming request. A thread pool is a pool of ready to use worker threads. The asynchronous operation is executed on this worker thread. Note that a worker thread is one that is executed in the background. An application can have only one application or main thread but multiple worker threads. Now, the worker thread is returned to the thread pool and when the asynchronous operation completes, the ASP.NET runtime is notified. Now the web server fetches another worker thread from the thread pool to process the remaining part of the request and executes the remaining request cycle. Note that this worker thread can be the same that initiated the asynchronous operation, or, it can be a different worker thread.
Implementing Asynchronous Operations in ASP.NET MVC Applications
To implement operations in ASP.NET MVC Framework you should extend your controllers from the abstract AsyncController
class. Here’s how this class looks like:
public abstract class AsyncController : Controller, IAsyncManagerContainer, IAsyncController, IController { protected AsyncController(); public AsyncManager AsyncManager { get; } protected virtual IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state); protected virtual IAsyncResult BeginExecuteCore(AsyncCallback callback, object state); protected override IActionInvoker CreateActionInvoker(); protected virtual void EndExecute(IAsyncResult asyncResult); protected virtual void EndExecuteCore(IAsyncResult asyncResult); }
The AsyncManager
class belongs to the System.Web.Mvc.Async
namespace and provides the necessary operations for the AsyncController
class.
You can write your controller in ASP.NET MVC 2 by deriving from the AsyncController
class as shown below:
public class HomeController : AsyncController { //Some code }
Note that the name of an asynchronous controller class should have the “Controller
” suffix. As an example, Home controller can be named HomeController
but not “Home
” or “ControllerHome
“. Also, you cannot have both the synchronous and asynchronous versions of the same method reside in the same controller. As an example, you cannot have “Index
” and “IndexAsync
” reside in the same controller
class. If you do, an AmbiguousMatchException
exception will be thrown as the synchronous and asynchronous versions of the same action method will have the same signature.
The following code snippet illustrates a synchronous controller and its action method:
public class ProductsController: Controller { public ActionResult LatestProducts(int productCode) { //Some code } }
To convert the above action method to an asynchronous action method, all you have to do is, extend the controller from the AsyncController
class and rename the action method with “Async
” suffix. Here’s how you can rewrite it:
public class ProductsController: AsyncController { public ActionResult LatestProductsAsync(int productCode) { //Some code } }
The actions that execute asynchronously are methods of a class that extends the AsyncController
class. An async action comprises of a pair of two methods that have the “Async” and “Completed” suffixes respectively.
public class HomeController : AsyncController { public void GetProductsAsync() { //Some code } public ActionResult GetProductsCompleted(IList<Product> items) { //Some code } }
Also, to define a route to handle a request asynchronously, use the AsyncMvcRouteHandler
, instead of usual MvcRouteHandler
as shown below:
routes.Add(new Route("Default.aspx", new AsyncMvcRouteHandler()) { Defaults = new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }), });
Suggested Readings
http://weblogs.asp.net/scottgu/archive/2010/01/10/asp-net-mvc-2.aspx
http://www.asp.net/mvc/whatisaspmvc
Summary
Asynchronous operations if used judiciously can help you improve the scalability and user experience of an application. You can use asynchronous operations in ASP.NET MVC applications to improve the user experience and application’s scalability. In this article we have had a look at synchronous and asynchronous operations and how the later can be implemented in ASP.NET MVC applications.