Dependency Injection in ASP.NET MVC NerdDinner App using Unity 2.0
In my previous post
Dependency Injection in ASP.NET MVC NerdDinner App using
Ninject, we did dependency injection in NerdDinner application
using Ninject. In this post, I demonstrate how to apply
Dependency Injection in ASP.NET MVC NerdDinner App using
Microsoft Unity Application Block (Unity) v 2.0.
Unity 2.0
Unity 2.0 is available on Codeplex at
http://unity.codeplex.com
. In earlier versions of Unity, the ObjectBuilder generic
dependency injection mechanism, was distributed as a
separate assembly, is now integrated with Unity core
assembly. So you no longer need to reference the
ObjectBuilder assembly in your applications. Two additional
Built-In Lifetime Managers - HierarchicalifetimeManager and
PerResolveLifetimeManager have been added to Unity 2.0.
Dependency Injection in NerdDinner using Unity
In my
Ninject post on NerdDinner, we have discussed the interfaces and concrete types of
NerdDinner application and how to inject dependencies
through controller constructors. The following steps will
configure Unity 2.0 to apply controller injection in
NerdDinner application.
Step 1 – Add reference for Unity Application Block
Open the NerdDinner solution and add reference
to Microsoft.Practices.Unity.dll and
Microsoft.Practices.Unity.Configuration.dll
You can
download Unity from at
http://unity.codeplex.com
.
Step 2 – Controller Factory for Unity
The
controller factory is responsible for creating controller
instances.We extend the built in default controller factory
with our own factory for working Unity with ASP.NET MVC.
public class UnityControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext reqContext, Type controllerType)
{
IController controller;
if (controllerType == null)
throw new HttpException(
404, String.Format(
"The controller for path '{0}' could not be found" +
"or it does not implement IController.",
reqContext.HttpContext.Request.Path));
if (!typeof(IController).IsAssignableFrom(controllerType))
throw new ArgumentException(
string.Format(
"Type requested is not a controller: {0}",
controllerType.Name),
"controllerType");
try
{
controller = MvcUnityContainer.Container.Resolve(controllerType)
as IController;
}
catch (Exception ex)
{
throw new InvalidOperationException(String.Format(
"Error resolving controller {0}",
controllerType.Name), ex);
}
return controller;
}
}
public static class MvcUnityContainer
{
public static IUnityContainer Container { get; set; }
}
Step 3 – Register Types and Set Controller Factory
private void ConfigureUnity()
{
//Create UnityContainer
IUnityContainer container = new UnityContainer()
.RegisterType<IFormsAuthentication, FormsAuthenticationService>()
.RegisterType<IMembershipService, AccountMembershipService>()
.RegisterInstance<MembershipProvider>(Membership.Provider)
.RegisterType<IDinnerRepository, DinnerRepository>();
//Set container for Controller Factory
MvcUnityContainer.Container = container;
//Set Controller Factory as UnityControllerFactory
ControllerBuilder.Current.SetControllerFactory(
typeof(UnityControllerFactory));
}
Unity 2.0 provides a fluent interface for type configuration. Now you can call all the methods in a single statement.The above Unity configuration specified in the ConfigureUnity method tells that, to inject instance of DinnerRepositiry when there is a request for IDinnerRepositiry and inject instance of FormsAuthenticationService when there is a request for IFormsAuthentication and inject instance of AccountMembershipService when there is a request for IMembershipService. The AccountMembershipService class has a dependency with ASP.NET Membership provider. So we configure that inject the instance of Membership Provider.
After the registering the types, we set
UnityControllerFactory as the current controller factory.
//Set container for Controller Factory
MvcUnityContainer.Container = container;
//Set Controller Factory as UnityControllerFactory
ControllerBuilder.Current.SetControllerFactory(
typeof(UnityControllerFactory));
When you register a type by using the RegisterType
method, the default behavior is for the container to use a
transient lifetime manager. It creates a new instance of the
registered, mapped, or requested type each time you call the
Resolve or ResolveAll method or when the dependency
mechanism injects instances into other classes.
The following are the LifetimeManagers provided
by Unity 2.0
ContainerControlledLifetimeManager - Implements a singleton behavior for objects. The object
is disposed of when you dispose of the container.
ExternallyControlledLifetimeManager - Implements a singleton behavior but the container doesn't
hold a reference to object which will be disposed of when
out of scope.
HierarchicalifetimeManager -
Implements a singleton behavior for objects. However, child
containers don't share instances with parents.
PerResolveLifetimeManager - Implements a behavior similar to the transient lifetime
manager except that instances are reused across build-ups of
the object graph.
PerThreadLifetimeManager - Implements a singleton behavior for objects but limited
to the current thread.
TransientLifetimeManager - Returns a new instance of the requested type for each
call. (default behavior)
We can also create
custome lifetime manager for Unity container. The following
code creating a custom lifetime manager to store container
in the current HttpContext.
public class HttpContextLifetimeManager<T> : LifetimeManager, IDisposable
{
public override object GetValue()
{
return HttpContext.Current.Items[typeof(T).AssemblyQualifiedName];
}
public override void RemoveValue()
{
HttpContext.Current.Items.Remove(typeof(T).AssemblyQualifiedName);
}
public override void SetValue(object newValue)
{
HttpContext.Current.Items[typeof(T).AssemblyQualifiedName]
= newValue;
}
public void Dispose()
{
RemoveValue();
}
}
Step 4 – Modify Global.asax.cs for configure Unity
container
In the Application_Start event, we call the ConfigureUnity method for configuring the Unity container and set controller factory as UnityControllerFactory
void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MobileCapableWebFormViewEngine());
ConfigureUnity();
}
Download Code
You can download the modified NerdDinner code from http://nerddinneraddons.codeplex.com