Why do I need dependency injection?
Lot's of people have written lot's about why dependency injection is required. I am not going to repeat all that, just a few points that I think, cannot be ignored
- Configuration flexibility - alternative implementations of a given service can be used without recompiling code
- Testability - Since we can provide alternative implementation of any given service at any time, any class can be unit tested very easily and effectively. Its easy to inject a fack implementation of a service in the class we want to unit test
- Reduction of Boiler plate code - Since we no longer need to create instances of classes and inject them with proper dependencies
- Promotes loose coupling between classes and subsystems - Since classes are not dependent on a specific implementation, they are dependent on the contract that the other classes expose.
Alright, so we need dependency injection, what next?
How do we implement dependency injection? Should we hand code the logic and create our own way of doing dependency injection?
Well, take my advice, never ever, never every do that! Always look for options, you will surely find one depdendency injection framework/container that suites your requirements. Even if it does not fit your requirement completely, I am sure the framework/container provides enough hooks, based on which you can customize it to you taste!
In the year 2011 and beyond, you cannot be serious if you are wasting your time and someone Else's money writing a dependency injection framework (I know a few people who have done that, can you believe it!)
What is Spring.NET?
Spring.NET is an awesome dependency injection framework (actually its lot more than that). Its open-source and its design is based on the proven Java based Spring Framework. The breath of functionality in Spring .NET spans application tiers which allows you to treat it as a "one stop shop" but that is not required. The best thing about Spring .NET is, its not an all-or-nothing solution. You can use the functionality in its modules independently. Spring.NET integrates with a lot of other projects like NHibernate, NUnit, Active MQ, Quartz .NET, Velocity etc.
Enough about Spring.NET, if you want to know more details about Spring.NET, I strongly recommend visiting this site, it has all the info you need. It has links to the latest documentation, blogs, articles, faq's etc.
By this time we agree that, we should use a dependency injection framework and for the sake of this post, I am going to show how easily we can integrate the Spring.NET dependency injection framework in our MVC3 application. Lets not waste any more time and jump into the code straightaway to get this part started, shall we!
How do they do it?
To Integrate Spring.NET into the MVC3 application you will need to do the following steps
- Add the Spring.NET dependencies to the project.
- Make the web.cofig changes to register the spring context
- Declare the dependencies in an xml file
- Write the code to interact with the dependencies in the HomeController
- Inherit the Global class in the Global.asax.cs file from Spring.Web.Mvc.SpringMvcApplication
Add the spring.net dependencies to the project
For integrating Spring.NET in your MVC3 application you will need to add references of following Spring.NET assemblies.
Make the web.config changes to register the spring context
In this step we add a <configSection> for the Spring.NET configuration. In the spring config section we would like to register the spring context. Update web.config should look like
What we are doing here is, telling Spring.NET to look for a file called web.xml inside the Config directory.
What will the web.xml file contain?
It will contain the dependency injection configurations for the classes in our application.
Declare the dependencies in an xml file
Spring will search for a file named web.xml inside the Config directory, directly under the root of you application. Lets make sure, Spring finds the file. Create a directory called Config at the root level of your MVC3 application and create a file called web.xml inside it. The project structure should look somewhat like this
|Project Structure with web.xml included in the project|
The web.xml is just a plain XML file that uses Spring.NET xml schema to inject the AccountService into the HomeController. We have given an id to the HomeController its Home in our case. We are also declaring that HomeController has a property Called AccountService. This property will be auto injected by the Spring.NET container with the reference of type AccountService.
Notice that the HomeController is not a singleton class. MVC3 framework creates a new instance of the Controller every time a request comes for that controller. Hence, Spring needs to know that, the HomeController is not supposed to be a singleton class. This is done by adding the attribute singleton="false" in the declaration of the HomeController.
The next declaration in the web.xml is that of AccountService. For the sake of this example this class has no dependencies. For our example this class is going to be very simple it will return some hard coded values.
Notice that the singleton attribute has not be specified for the declaration of AccountService. By default the singleton value is true, this means that the AccountService is a singleton class. Spring.NET will instantiate only one instance of the AccountService for the entire application!
Write the code to interact with the dependencies in the HomeController
As seen in Step - 2, HomeController is going to have a property of type AccountService. We are going to query the AccountService to get the user count which will be eventually be shown on the UI.
As you can see there is no magic in our classs. HomeController simply calls the AccountService to get the UserCount and sets the value in the ViewBag. The AccountService implementation is extremely simple, it returns a hardcoded value of 5454.
Lets look at the view SpringIndex.cshtml that will show the UserCount from the ViewBag.
As you must have guessed, the view could not have been any simpler. It simply shows the message with the UserCount in it.
Inherit the Global class in the Global.asax.cs file from Spring.Web.Mvc.SpringMvcApplication
We are almost done with all the plumbing required to integrate Spring.NET with MVC3 but, one last thing is left. We need to inherit our Global class in the Global.asax.cs file from Spring.Web.Mvc.SpringMvcApplication instead of System.Web.HttpApplication. This is required so that Spring registers the controller factory to instantiate the Controllers when the request comes. This is done so that Spring gets an opportunity to dependency inject the controllers.
And we are done! Lets run the application and browse the URL /Home/SpringIndex to see what happens. If you have followed the post till this point, browsing the url will result in a page like this
|SpringIndex renders with UserCount value|
When the request for SpringIndex action of the HomeController comes to the server following things occur
- Spring intercepts the call and instantiates HomeController
- Injects all the dependencies of HomeController i.e. AccountService in our case
- Calls the action method SpringIndex to complete the request
- SpringIndex method calls the AccountService to get the UserCount and sets it in the ViewBag
- SpringIndex.cshtml is rendered which shows UserCout!