Introduction
Ever since I started using Composite WPF for both WPF and Silverlight, I’ve grown a liking towards Unity as a inversion of control container. It provides a clean way of injecting dependencies into components where I need those dependencies, without having to provide a large amount of configuration.
Since Unity works so well for WPF and Silverlight I thought I should give it a go inside an ASP.NET application. In this article I’m going to show what happened next and what the end result looks like.
Page behavior
Most developers working on a web application build in ASP.NET will be using pages as the main form of interaction with users of the application. So using Unity to inject dependencies directly into pages will provide the most ‘bang for the buck’ for developers. Especially since this will allow developers to keep on working with the pages as if Unity never existed. Also integrating the unity container in this way should make swapping it out for another container a lot easier to do.
As a developer we all know aspx pages as two parts, one is the .aspx file and one code-behind file which becomes a class when the web project is compiled. However there’s more to this. When the page is compiled it isn’t complete, in the sense that the markup in the aspx file does nothing on its own. At the moment the user requests the page from the webserver, a build provider is used to combine the already compiled class with the markup in the aspx file. The markup in the aspx file is read and converted into Response.Writeline actions and other logic required to make the page behave the way the developer designed it. The compiled result is no longer a page, but rather a http handler that behaves like any other http handler in ASP.NET. The construction of the compiled page handler is done by the PageHandlerFactory class.
Extending the PageHandlerFactory
Because ASP.NET uses the PageHandlerFactory to create the http handler (which is the page) I can extend its behavior to make use of the Unity container to inject dependencies into the page. Below is a sample of the new UnityPageHandlerFactory class which will inject the dependencies into the page once it’s compiled and constructed.
1: public class UnityPageHandlerFactory : PageHandlerFactory
2: {
3: public override System.Web.IHttpHandler GetHandler(System.Web.HttpContext context, string requestType, string virtualPath, string path)
4: {
5: var handler = base.GetHandler(context, requestType, virtualPath, path);
6:
7: // The handler represents an actual page so it's possible to inject dependencies here.
8: ApplicationContext.Container.BuildUp(handler.GetType(),handler);
9:
10: return handler;
11: }
12: }
The ApplicationContext class used in this class is there to make it possible to add types and instances to the unity container from code, rather than using configuration. I’ve also made it possible to configure the container in the web.config file. I can really recommend using web.config here to configure most of the common types used by the pages. The main reason for this is that configuration through code can be a bit problematic. You’ll need a global.asax file and add the code to the Application_Start event to be in the right place before any page is constructed. This is about as much work as is needed to setup a correct configuration in the web.config file.
A sample of this configuration is shown below.
1: <configSections>
2: <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
3: </configSections>
4: <unity>
5: <containers>
6: <container>
7: <types>
8: <type type="UnityWebSample.ISampleDataProvider, UnityWebSample" mapTo="UnityWebSample.SampleDataProviderImplementation, UnityWebSample"/>
9: </types>
10: </container>
11: </containers>
12: </unity>
By default ASP.NET does not pick the new page handler factory. To achieve this the old handler factory needs to be removed and the new one needs to be added. The following snippet demonstrates how this can be done.
1: <httpHandlers>
2: <remove verb="*" path="*.aspx"/>
3: <add verb="*" path="*.aspx" type="UnityWebIntegration.UnityPageHandlerFactory, UnityWebIntegration"/>
4: </httpHandlers>
What about generic http handlers?
Building simple HTTP handlers is done by the SimpleHandlerFactory. This one however is internal and cannot be overridden. The functionality however can be copied and is nothing more than asking the BuildManager class to create the HTTP handler for you.
1: public class UnitySimpleHandlerFactory : IHttpHandlerFactory
2: {
3: public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
4: {
5: // Build the requested http handler and return it to the caller
6: var vPathBuildResult = BuildManager.CreateInstanceFromVirtualPath(pathTranslated, typeof(IHttpHandler));
7: ApplicationContext.Container.BuildUp(vPathBuildResult.GetType(), vPathBuildResult);
8:
9: return (IHttpHandler)vPathBuildResult;
10: }
11:
12: public virtual void ReleaseHandler(IHttpHandler handler)
13: {
14:
15: }
16: }
You can use the following snippet to configure the Unity version of the SimpleHandlerFactory.
1: <httpHandlers>
2: <remove verb="*" path="*.ashx"/>
3: <add verb="*" path="*.ashx" type="UnityWebIntegration.UnitySimpleHandlerFactory, UnityWebIntegration"/>
4: </httpHandlers>
Conclusion
Combining Unity with ASP.NET delivers the power of Unity, but without the hassle of having to use specific base types in your pages. This leaves the Visual Studio default behavior and for me that’s always a nice bonus.
For more information on unity and extending asp.net:
3 comments
Very helpful. Many thanks.
What if we’re dealing with web service? How can we make a custom handler?
dencio ango-ango
If you’re using WCF you can create a custom HostFactory and reference that in the svc file that is associated with the service. If of course you’re using IIS to host the WCF service.
If you are hosting the service inside a custom host you can construct the instance of the service using unity and provide that instance to the constructor of ServiceHost.
willemm
Thanks for the quick reply.
I’m using an ASP.NET web service. Not WCF.
Usually I use ASP.NET MVC on my projects, however this project requires us to use ASP.NET Web Form.
IoC is working on web forms after I followed your blog (I thank you, dude). However it aint working on web service.
dencio ango-ango