About the book
This is
a sample chapter of the book
Dependency Injection in .NET. It has been published with
the exclusive
permission of Manning.
Written by: Mark Seemann
Pages: 375
Publisher: Manning
ISBN: 9781935182504
Get 40% discount
DotNetSlacker readers can get 40% off the full print book or ebook at
www.manning.com using the promo code dns40 at checkout.
ASP.NET MVC was built with the express intent to be DI-friendly, and it is. It doesn't enforce the use of DI, but it easily allows it without making any assumption on the
kind of DI you will apply. You can use Poor Man's DI or whichever DI Container you would like.
ASP.NET MVC extensibility
As is always the case with DI, the key to applying DI is to find the correct extensibility point. In ASP.NET MVC, this is an interface called IControllerFactory.
Figure 1 illustrates how it fits into the framework.
Figure 1: When the ASP.NET MVC runtime receives a request, it asks its Controller Factory to create a Controller for the requested URL. The Controller Factory determines
the correct type of Controller to use for the given request and creates and returns a new instance of that type. ASP.NET MVC then invokes the appropriate Action Method on the
Controller instance. When it’s done, ASP.NET MVC gives the Controller Factory a chance to dispose of resources by calling ReleaseController.

Controllers are a very central concept in ASP.NET MVC. They handle requests and determine how to respond. If you need to query a database,
validate and save incoming data, invoke Domain logic, and so on you initiate such actions from a Controller.
A Controller should not do such things itself but rather
delegate the work to appropriate Dependencies. This is where DI comes in. We want to be able to supply Dependencies to a given Controller class, ideally by
Constructor Injection. This is possible with a custom Controller Factory.
Creating a custom ControllerFactory
ASP.NET MVC comes with a DefaultControllerFactory that requires Controller classes to have a default constructor. That's a sensible default behavior that
doesn't force you to use DI if you don't want to. However, default constructors and Constructor Injection are mutually exclusive, so we need to modify this behavior by
implementing a custom ControllerFactory.
Doing so is not particularly hard. It requires you to implement the IControllerFactory interface:
The CreateController method provides you with a RequestContext that contains such information as the HttpContext, while
the controllerName indicates which Controller is requested.
You may choose to ignore the RequestContext and just use the controllerName
to determine which Controller to return. No matter what you do, this is the method where you get the chance to wire up all required Dependencies and supply them
to the Controller before returning the instance. I'll show you an example in the subsection.
If you created any resources that need to be explicitly disposed, you get the
chance to do that when the ReleaseController method is called.
TipDefaultControllerFactory implements IControllerFactory and has several virtual methods. Instead of implementing
IControllerFactory from scratch, it is often easier to derive from DefaultControllerFactory.
Although implementing a custom ControllerFactory is the hard part, it's not going to be used unless you tell ASP.NET MVC about it.
Registering your custom ControllerFactory
Custom ControllerFactories are registered as part of the application startup sequence - usually in Global.asax. It is done by calling
ControllerBuilder.Current.SetControllerFactory. Here's a snippet from the sample Commerce application.
In this example, we create and assign a new instance of the custom CommerceControllerFactory and pass it all the required and already created
Dependencies. ASP.NET MVC will now use controllerFactory instance as its ControllerFactory for this application.
Example: implementing CommerceControllerFactory
The Commerce sample application needs a custom ControllerFactory to wire up Controllers with the required Dependencies. Although the entire dependency
graph for all Controllers is considerably deeper, from the perspective of the Controllers themselves, the union of all immediate Dependencies is as small as three items,
as shown in figure 2.
Figure 2: Dependency graph for the three Controllers in the sample Commerce application. The concrete implementations of each of these Dependencies have other
Dependencies but these are not shown. BasketController and HomeController share a Dependency on CurrencyProvider. AccountController is inherited unchanged from the default
ASP.NET MVC template; since it uses Bastard Injection it has no unresolved dependencies.

Each of these Dependency implementations encapsulate other
Dependencies, but these are already wired up in Global.asax before they are passed to the CommerceControllerFactory, which itself uses Constructor
Injection (see listing 1).
Listing 1: Initializing CommerceControllerFactory
This is the standard application of the Constructor Injection pattern for three Dependencies injected through the constructor, protected by Guard
Clauses, and saved for later use in read-only fields.
Although we could implement IControllerFactory directly, it is easier to derive from
DefaultControllerFactory and override its GetControllerInstance method. This means that the DefaultControllerFactory still takes care
of mapping a Controller name to a Controller type, and all we have to do is to return instances of the requested types (see listing 2).
Listing 2: Creating Controllers
This method overrides DefaultControllerFactory.GetControllerInstance to create instances of the requested Controller types. If the
requested type is either BasketController or HomeController, we explicitly wire them up with their required Dependencies and return them. Both
use Constructor Injection so we supply the Dependencies through their constructors.
For those types not explicitly handled, we default to the base
behavior, which is to create the requested Controller using its default constructor. Notice that we are not explicitly handling AccountController so we let the
base behavior deal with it instead. AccountController is a carryover from the ASP.NET MVC project template and it uses Bastard Injection, which gives it a
default constructor.
NoteI consider Bastard Injection to be an anti-pattern, but I left AccountController in that state because I had plenty of other proper
DI examples to showcase. I did it because this is, after all, sample code, but I would never leave it like that in production code.
When a CommerceControllerFactory instance is registered in Global.asax, it will correctly create all requested Controllers with the required
Dependencies.
TipConsider not writing a custom ControllerFactory yourself. Instead, use a general-purpose ControllerFactory that works together with your DI Container of
choice. Take a look at the MVC Contrib project for inspiration, or simply use one of the reusable implementations available there.
The nice thing about ASP.NET MVC is that it was designed with DI in mind, so you only need to know and use a single extensibility point to enable DI for your
application.
Summary
Object Composition is one of three important dimensions of DI (the others being Lifetime Management and Interception). Some frameworks make it easy for
us. When writing console applications and Windows clients (WPF or Windows Forms) we are more or less in direct control of what is happening at the application's entry point.
This provides us with a distinct and easily implemented Composition Root right at the entry point.
Other frameworks like ASP.NET MVC or WCF make us work a little harder
but they still provide the Seams we can use to define how the application should be composed. ASP.NET MVC was designed with DI in mind, so composing an application is as easy as
implementing a custom IControllerFactory and registering it with the framework.
Get 40% discount
DotNetSlacker readers can get 40% off the full print book or ebook at
www.manning.com using the promo code dns40 at checkout.
About Manning Publications
 |
Manning Publication publishes computer books for professionals--programmers, system administrators, designers, architects, managers and others. Our focus is on computing titles at professional levels. We care about the quality of our books. We work with our authors to coax out of them the best writi...
This author has published 33 articles on DotNetSlackers. View other articles or the complete profile here.
|
You might also be interested in the following related blog posts
Building Distributed Applications in ASP.NET MVC at MvcConf 2010 on 7/22/2010
read more
MSDN Guidance on ASP.NET MVC vs WebForms and its Impact on my EF + ASP.NET Work
read more
Html Encoding Nuggets With ASP.NET MVC 2
read more
ASP.NET MVC2 Preview 2: Areas and Routes
read more
MvcContrib working on Portable Areas
read more
Auto-Start ASP.NET Applications (VS 2010 and .NET 4.0 Series)
read more
Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 25: ViewModel
read more
Video: DevExpress Plans For ASP.NET MVC
read more
Walking the tight rope
read more
MvcContrib version control has moved to GitHub
read more
|
|
Please login to rate or to leave a comment.