Async Actions in Monorail

time to read 2 min | 340 words

One of the ways to significantly increase the scalability of our applications is to start performing more and more things in an asynchronous manner. This is important because most actions that we perform in a typical application are not CPU bound, they are I/O bound.

Here is a simple example:

public class HomeController : SmartDispatcherController
{
	IUserRepository userRepository;
	
	public void Index()
	{
		PropertyBag["userInfo"] = userRepository.GetUserInformation(CurrentUser);
	}
}

GetUserInformation() is a web service call, and it can take a long time to run. Now, if we have the code as above, while the web service call is being processed, we can't use this thread for any other request. This has a significant implications on our scalability.

ASP.Net has support for just those scenarios, using async requests. You can read more about it here, including a better explanation of the

I recently added support for this to MonoRail (it is currently on a branch, and will be moved to the trunk shortly).

Let us say that you have found that the HomeController.Index() method is a problem from scalability perspective. You can now rewrite it like this:

public class HomeController : SmartDispatcherController
{
	IUserRepository userRepository;
	
	public IAsyncResult BeginIndex()
	{
		return userRepository.BeginGetUserInformation(CurrentUser, 
			ControllerContext.Async.Callback,
			ControllerContext.Async.State);
	}

	public void EndIndex()
	{
		PropertyBag["userInfo"] = userRepository.EndGetUserInformation(ControllerContext.Async.Result);
	}
}

That is all the change that you need to do to turn an action async. We are using the standard .NET async semantics, and MonoRail will infer them automatically and use the underlying ASP.Net async request infrastructure.

"BeginIndex/EndIndex" are the method pairs that compose the async method index. Note that the only thing that needs to be change is turning a synchronous action to an asynchronous action is splitting the action method into an IAsyncResult Begin[ActionName]() and void End[ActionName](). Everything else is exactly the same.

This is a major improvement for scaling an application. The more I learn about async programming, the more it makes sense to me, and I think that I am moving more and more to this paradigm.