Dependency injection is a process of supplying an external dependency to a component. In this article we will learn how to use StructureMap as our dependency injection container.
Scenario:
The scenario involves an ASP.NET MVC application and the creation of the controller. The controller has dependencies on two other objects.
Creating Controller Without Dependency Injection:
There are multiple ways of creating the controller with the dependencies in place even when a dependency injection tool is not used. One of the ways is to initialize the objects inside the default constructor of the controller as shown below:
The above code will initialize the UserRepository and the RoleRepository but now it is extremely hard to unit test against the RegistrationController. The main reason is that there is no way to inject the dependencies into the RegistrationController. The only possible way is to use reflection and populate private fields but that is an ugly solution.
Another solution is to override the GetControllerInstance method of the DefaultControllerFactory. The DefaultControllerFactory is responsible for initializing the controllers. Below you can see the implementation of the MyControllerFactory which takes over the control of creating controllers.
The RegistrationController now contains a new constructor which takes IUserRepository and IRoleRepository as shown below:
The problem with the above technique is that you are responsible for creating all the controllers and their dependencies. And if you have complex dependencies then you will spend a lot of time and effort to create all of them. It is much better to transfer this job to a dependency injection container whose main responsibility is to create and resolve dependencies.
Using Structuremap to Resolve Dependencies:
The first thing you need to do is to tell Structuremap about your dependencies. This should be performed at the start of the application. In the code below we are invoking the StructureMapConfiguration method from inside the Application_Start.
The ObjectFactory.Initialize method is responsible for registering the dependencies. As, you can see we are telling StructureMap that whenever we ask for IUserRepository then give us the concreate type UserRepository.
Now, you can retrieve the IUserRepository default implementations from StructureMap using the ObjectFactory.
Although you can use ObjectFactory.GetInstance<IUserRepository>() and ObjectFactory.GetInstance<IRoleRepository>() to retrieve the objects and use in your controller but it is a good idea to resolve the dependency of the root object which in our case is the RegistrationController.
In order to resolve the dependency of the root element we will need to use own version of ControllerFactory. The implementation of StructuremapControllerFactory is shown below:
We also need to tell our application to use StructuremapControllerFactory as the default ControllerFactory. This is implemented inside the Application_Start event of the application as shown below:
Now, if you run your application you will notice that the instances _userRepository and _roleRepository are instantiated by default.
Convention Over Configuration:
If you have only couple of dependencies then you can register them manually using the ForRequestedType and TheDefaultIsConcreteType methods. But if you are dealing with several dependencies then it is a good idea to use the Scan method of StructureMap.
The Scan method is responsible for parsing through the assembly and registering the assemblies according to the convention specified by the user. If there is no convention specified then the default convention is used. The default convention registers all the interfaces and their concrete types according to the naming convention. This means IFoo will be registered with the concrete type Foo. In other words IInterfaceName will be registered with the matching ConcreteTypeName.
The Scan implementation is shown below:
The above code will scan the "MyMVCApplication" assembly and registers all the dependencies. You do not have to register the dependencies manually.
Conclusion:
In this article we learned how to use dependency injection in an ASP.NET application using StructureMap. In the next article we are going to dive deeper into the StructureMap API and learn how to provide constructor arguments to the dependent objects.
Download Sample:
You can download the sample by cloning the following repository:
[email protected]:azamsharp/EStudy.git
References:
1) StructureMap Official Website
2) EStudy Part 2: Setting Up Controller Factory Using StructureMap