Introduction
This article discusses how you may handle the lifespan of a controller when you use the Managed Extensibility Framework (MEF) in ASP.NET MVC 3 applications.
You’ll benefit from this article if you have some understanding and knowledge of MEF and you’ve read ExportAttribute,
ImportAttribute, CompositionContainer, and MEF in ASP.NET MVC 3. The article does not deal with the intricacies of MEF or the ASP.NET MVC 3 system.
The story is accompanied with downloadable Visual Studio solutions:
In August 2011, you should consider the following software:
- Visual Studio 2010
- Visual Studio 2010 SP1
- .NET Framework 4.0
- ASP.NET MVC 3
- C# 4.0.
If you run a plain vanilla ASP.NET MVC 3 application, whenever an HTTP request is made, for example when a user clicks a link on the screen, the ASP.NET MVC 3 system
creates a fresh instance of the specified controller class. This fact often eludes an unsuspecting developer when he utilizes MEF in his application.
The lack of foresight manifests itself with a rude message saying “a single instance of controller ‘xxx’ cannot be used to handle multiple requests”.
Figures 1 and 2 illustrate what happens if you use MEF, but you don’t handle the lifespan of your controller properly.
Figure 1 — ASP.NET MVC 3 application with MEF. A user has requested the Index page.
MEF creates an instance of the HomeController
class. The ASP.NET MVC 3 system emits HTML and sends it to the user’s browser. The user clicks the Create New link.
The click results in a new HTTP request. To show the Create page, the ASP.NET MVC 3 system needs a fresh instance of the HomeController
class, but MEF hasn’t produced
a new controller object. In Figure 2, the ASP.NET MVC 3 system responds to the user’s click, reflecting this flaw.
Figure 2 — ASP.NET MVC 3 application with MEF. Error message in response to user’s click.
You can download the Mvc3MefLifespanError solution
that demonstrates the problem of incorrect management of the controller’s lifespan.
You have at least two options to rectify the problem in MEF:
- You use
PartCreationPolicyAttribute
; or
- You alternate the construction and destruction of a composition container at each page request.
Option 1 — PartCreationPolicyAttribute usage
In Example 1, I mark the HomeController
class with PartCreationPolicyAttribute(CreationPolicy.NonShared)
. CreationPolicy.NonShared
instructs MEF
that it should create a new instance of the HomeController
class whenever the application needs a HomeController
object.
Example 1 — PartCreationPolicyAttribute adorns the HomeController class.
[
ExportAttribute
,
PartCreationPolicyAttribute(CreationPolicy.NonShared)
]
public class HomeController : Controller
{
[ImportingConstructorAttribute]
public HomeController(MessageSource messageSource)
{
this.messageSource = messageSource;
}
.
.
.
}
The complete Visual Studio Mvc3MefLifespanPartCreationPolicy
solution demonstrates the creation policy attribute.
There is widespread belief among MEF developers that, by default, a composition container creates, in Microsoft parlance, single parts or singleton objects.
The truth is that the default creation policy is CreationPolicy.Any
. However, there is a trick to CreationPolicy.Any
.
If the importing entity doesn’t specify its preference, the composition container produces a single object.
This explains why I get the error (see Figure 2) when I run the Mvc3MefLifespanError sample solution. Since I don’t specify a creation policy,
the policy is CreationPolicy.Any
, by default. However, in the absence of the importing entity, the composition container creates a single instance
of the HomeController
class and supplies it to the ASP.NET MVC 3 system for each HTTP page request.
Option 2 — Construction and destruction of a composition container at each page request
When the ASP.NET MVC 3 system processes an HTTP request, it asks your custom dependency resolver to fetch objects from your MEF composition container. When you fetch
an object from the container, the container satisfies all imports with relevant exports.
I avail myself of this feature by providing methods that will respond to the HttpApplicantion.BeginRequest
and HttpApplicantion.EndRequest
events.
In Example 2, I present a different implementation of the IDependencyResolver
interface from the one I show in Example 12
of the ExportAttribute, ImportAttribute, CompositionContainer, and MEF in ASP.NET MVC 3 article.
Instead of a private variable that is initialized in the constructor, I have a static CompositionContainer
property.
Example 2 — MefDependencySolver class with the static CompostionContainer property.
namespace MefLifespanMvc03
{
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Web.Mvc;
public class MefDependencySolver : IDependencyResolver
{
public static CompositionContainer CompositionContainer { get; set; }
public object GetService(Type serviceType)
{
string name = AttributedModelServices.GetContractName(serviceType);
return CompositionContainer.GetExportedValueOrDefault<object>(name);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return CompositionContainer.GetExportedValues<object>(serviceType.FullName);
}
}
}
In Example 3, I define the Application_BeginRequest
method in the MvcApplication
class. When an HTTP request is initiated, the ASP.NET MVC 3 system invokes
the method, setting the CompositionContainer
property of my custom dependency resolver to a newly created instance of a CompositionContainer
.
Example 3 — Creates a new instance of CompositionContainer.
protected void Application_BeginRequest()
{
TypeCatalog typeCatalog = new TypeCatalog(typeof(HomeController),
typeof(MessageSource));
MefDependencySolver.CompositionContainer =
new CompositionContainer(typeCatalog);
}
In Example 4, I define the Application_EndRequest
method in the MvcApplication
class. When the HTTP request has completed,
the ASP.NET MVC 3 system invokes the method, destructing the CompositionContainer
of my custom dependency resolver.
Example 4 — Destroys the CompositionContainer.
protected void Application_EndRequest()
{
MefDependencySolver.CompositionContainer.Dispose();
}
The technique of constructing/destructing a composition container allows you to ignore MEF part creation policies, but it requires that you write more code
in the MvcApplication
class. The technique has an additional advantage, to wit, it prevents memory leaks that may occur very easily if you are not careful.
I’ve enclosed the complete Mvc3MefLifespanCompositionContainer
solution to demonstrate the construction/destruction technique, in the downloadable package.
Summary
If you use MEF in your ASP.NET MVC 3 application, beware of its pitfalls. You need to handle the lifespan of your controllers. The article demonstrates two techniques.
You can use PartCreationPolicyAttribute
, or create and dispose the composition container as your application responds to BeginRequest
and EndRequest
events.
A nice thing about the creation/disposal technique is that you also avoid potential memory leaks.