Writing ASP.NET MVC bootstrapper with Autobox

This will post will show how you can use AutoBox to easily write a bootstrapper for ASP.NET MVC. I have used the latest version of AutoBox (available from nuget, this version also includes Castle.Windsor internally for managing dependencies rather using its own resolver and does not require interface to type naming convention [IAccountRepository –> AccountRepository]) . To understand what is AutoBox , how you can use it for caching using memcached and let it automatically handle dependencies for controllers and repositories, i would recommend to take a look at this post:

http://weblogs.asp.net/mehfuzh/archive/2011/11/06/introducing-autobox-on-the-fly-dependency-injection-and-caching-container.aspx

Moving forward , let’s consider a simple bootstrapper interface:

  1. public interface IBootStrapperTask
  2. {
  3.     void Execute();
  4. }

The Execute()  method will be invoked during initialization for registering routes, controllers, mappings (AutoMapper), etc. We will have one static factory (Ex. BootStrapper)  that will initiate it through CommonServiceLocator.

  1. public static class BootStrapper
  2. {
  3.     /// <summary>
  4.     /// Executes registered tasks.
  5.     /// </summary>
  6.     public static void Execute()
  7.     {
  8.         ServiceLocator.Current.GetAllInstances<IBootStrapperTask>().ToList().ForEach(task =>task.Execute());
  9.     }
  10. }

A typical example of a bootstrapping task could be RegisterRoutes:

  1. public class RegisterRoutes : IBootStrapperTask
  2. {
  3.     private readonly RouteCollection routes;
  4.  
  5.     /// <summary>
  6.     /// Intializes the new instance of <see cref="RegisterRoutes"/> class.
  7.     /// </summary>
  8.     public RegisterRoutes()
  9.         : this(RouteTable.Routes)
  10.     {
  11.         // intentionally left blank.
  12.     }
  13.  
  14.     /// <summary>
  15.     /// Intializes the new instance of <see cref="RegisterRoutes"/> class.
  16.     /// </summary>
  17.     internal RegisterRoutes(RouteCollection routes)
  18.     {
  19.         this.routes = routes;
  20.     }
  21.  
  22.     public void Execute()
  23.     {
  24.         routes.Clear();
  25.  
  26.         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  27.         routes.IgnoreRoute("{*favicon}", new {favicon = @"(.*/)?favicon.ico(/.*)?"});
  28.  
  29.         Routes.Register(routes);
  30.     }
  31.  
  32. }

Here on line 29, i have added Routes.Register which is similar to the BootStrapper.Execute() that further narrows down to specific routing classes. For example. AccountRoutes.

  1. public static void Register(RouteCollection routes)
  2. {
  3.     ServiceLocator.Current.GetAllInstances<IRoutesRegistration>().ToList()
  4.        .ForEach(task => task.Register(routes));
  5. }

The code inside Routes class again pretty straight forward and exactly identical to BootStrapper except the IRoutesRegistration interface. We can also have RegisterControllers but since the dependencies are automatically wired by AutoBox, we only need to specify (if required) what repository methods to be data cached and for what duration.

  1. public class RegisterControllers : IBootStrapperTask
  2. {
  3.     void IBootStrapperTask.Execute()
  4.     {
  5.         Container.Setup<ProductRepository>(x => x.GetProductDetails(0)).Caches(TimeSpan.FromMinutes(1)).VaryByArgs();
  6.         ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
  7.     }
  8. }

More on caching and how MyControllerFactory should look like; please check my previous post as well as the product documentation. Finally, it’s about gluing the whole thing together and we just need to have these lines in global.asax.cs

  1. protected void Application_Start()
  2. {
  3.     // Initalizes autobox self.
  4.     Container.Init();
  5.     BootStrapper.Execute();
  6. }

When you will run the project; if you followed the flow then it should work as you have expected it. The project page for AutoBox can be reached here: http://mehfuzh.github.com/AutoBox/ .

 

Hope that helps

Assert the order of expected calls over instances

How you assert through unit test that an user is authenticated before doing withdraw operation? You can surely verify a method is invoked as expected but if you want to ensure the order right then you might require a little more. JustMock lets you specify the order in which your setups should be executed. This helps you identify the exact way in which a particular logic is implemented.

To begin, lets consider the following context:

User wants to withdraw money from his account. Withdraw operation should validate the following goals:

  • It should check if the user is authenticated
  • It should get the balance for the authenticated user and check if the amount to be withdrawn is less than or equals to what is specified.
  • Do the withdraw operation and return the remaining balance.

Now we have one IUserService interface

  1. public interface IUserSerivce
  2. {
  3.     bool IsAuthenticated { get; }
  4.     IUser GetUser();
  5.  
  6. }

One IAccountService interface to process the accounts operation:

  1. public interface IAccountService
  2. {
  3.     double Withdraw(double amount);
  4.     double GetBalance(IUser user);
  5. }

The basic AccountRepository class with minimal implementation covering the above context looks like:

  1. public class AccountRepsotory
  2.      {
  3.          public AccountRepsotory(IUserSerivce userService, IAccountService accountService)
  4.          {
  5.              this.userService = userService;
  6.              this.accountService = accountService;
  7.          }
  8.  
  9.          public virtual double Withdraw(double amount)
  10.          {
  11.              if (userService.IsAuthenticated)
  12.              {
  13.                  if (accountService.GetBalance(userService.GetUser()) >= amount)
  14.                  {
  15.                      return accountService.Withdraw(amount);
  16.                  }
  17.              }
  18.  
  19.              throw new ArgumentException("TODO");
  20.          }
  21.  
  22.          private readonly IUserSerivce userService;
  23.          private readonly IAccountService accountService;
  24.      }

Ensuring every step to be executed in an orderly manner , we just need to specify an extra InOrder option in Mock.Arrange that will otherwise fail the test during assert for any change of the expected execution order.

  1. [TestMethod]
  2. public void ShouldCheckUserAndBalanceInOrderWhenSpecificAmountIsWithdrawn()
  3. {
  4.     var userService = Mock.Create<IUserSerivce>();
  5.     var accountService = Mock.Create<IAccountService>();
  6.     
  7.     var user = Mock.Create<IUser>();
  8.  
  9.     Mock.Arrange(() => userService.IsAuthenticated).Returns(true).InOrder();
  10.     Mock.Arrange(() => userService.GetUser()).Returns(user).InOrder();
  11.     Mock.Arrange(() => accountService.GetBalance(user)).Returns(1000).InOrder();
  12.  
  13.     Mock.Arrange(() => accountService.Withdraw(Arg.AnyDouble)).Returns((amount) => 1000 – amount).InOrder();
  14.  
  15.  
  16.     var repository = new AccountRepsotory(userService, accountService);
  17.  
  18.     Assert.AreEqual(990, repository.Withdraw(10));
  19.  
  20.     Mock.Assert(userService);
  21.     Mock.Assert(accountService);
  22. }

Let’s remove the line# 13 from AccountRepository.Withdraw  that yields:

  1. public virtual double Withdraw(double amount)
  2. {
  3.     if (userService.IsAuthenticated)
  4.     {
  5.         return accountService.Withdraw(amount);
  6.     }
  7.  
  8.     throw new ArgumentException("TODO");
  9. }

 

Since we broke the order, the test will fail with the following message:

image

 

Here one thing to notice that InOrder is applied to different mock instances within the test method scope that makes it effective in most practical and wide variety of scenarios. I have used Q3 SP build for the purpose (Also available via NuGet).

 

Hope that helps