My favorites | Sign in
Logo
                
Search
for
Updated Aug 09, 2009 by nicholas.blumhardt
AspNetIntegration  
ASP.NET integration provides dependency injection for WebForms pages.

Introduction

In an ASP.NET application, the WebForms framework creates pages and controls using reflection in a way that cannot be intercepted for constructor injection to be performed. Property injection is the best available strategy, and Autofac provides the Autofac.Integration.Web library to achieve flexible property injection for ASP.NET pages and user controls.

Using ASP.NET MVC

This wiki page covers generic integration and WebForms, for ASP.NET MVC see MvcIntegration.

Typical Configuration

Referenced Assemblies

For ASP.NET to work with Autofac, both Autofac.dll and Autofac.Integration.Web.dll must be referenced by the application or placed in the /Bin directory.

Web.config

The next step is to add the Autofac HTTP Modules to the Web.config file:

<configuration>
  <system.web>
    <httpModules>
      <add name="ContainerDisposal" type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web"/>
      <add name="PropertyInjection" type="Autofac.Integration.Web.PropertyInjectionModule, Autofac.Integration.Web"/>

The Container Disposal Module lets Autofac dispose of any components created during request processing as soon as the request completes. The Property Injection Module injects dependencies into pages before the page lifecycle executes. (An alternative Unset Property Injection module is also provided.)

IIS 7+ Note: The Autofac configuration may need to appear in the modules section in order to work in integrated (vs. classic) pipeline mode. See http://groups.google.com/group/autofac/browse_thread/thread/6331896f85e685b1.

Global.asax

The dependency injection modules expect that the HttpApplication instance supports IContainerProviderAccessor. A complete global application class is shown below:

public class Global : HttpApplication, IContainerProviderAccessor
{
  static IContainerProvider _containerProvider;

  protected void Application_Start(object sender, EventArgs e)
  {
    var builder = new ContainerBuilder();
    builder.Register<SomeDependency>().FactoryScoped();
    _containerProvider = new ContainerProvider(builder.Build());
  }

  public IContainerProvider ContainerProvider
  {
    get { return _containerProvider; }
  }
}

IContainerProvider exposes two useful properties: ApplicationContainer and RequestContainer. The first is the root container that was built at application start-up. The second, RequestContainer should be used whenever manual dependency resolution/service lookup is required. The components that it contains (apart from any singletons) will be specific to the current request.

Wiring up Components

To configure one-per-HTTP-request instance scope, use the ContainerScoped() scope configuration method.

As of Autofac 1.3, the HttpRequestScoped() extension method in the Autofac.Integration.Web namespace will have the same effect.

Implementing WebForms Pages and User Controls

Pages and UserControls that require dependencies should expose their dependencies as public properties:

// MyPage.aspx.cs

public partial class MyPage : Page
{
  public IFoo SomeDependency { get; set; }

  protected void Page_Load(object sender, EventArgs e)
  {
    // SomeDependency will be set by Autofac.
    // In a production application the property accessor would check for null.
    label1.Text = SomeDependency.SomeMessage;
  }
}

Explicit Configuration

When adding dependency injection to an existing application, it is usually necessary to distinguish between pages that will have their dependencies injected, and those that will not. The InjectPropertiesAttribute attribute in Autofac.Integration.Web, coupled with the AttributedInjectionModule help to achieve this.

First, replace the PropertyInjection HTTP Handler with the AttributedInjection handler:

<add name="AttributedInjection" type="Autofac.Integration.Web.AttributedInjectionModule, Autofac.Integration.Web"/>

Once this is in place, pages and controls will not have their dependencies injected by default. Instead, they must be marked:

[InjectProperties]
public partial class MyPage : Page
{
  // ...

Integrating by Hand (Base Page and Control Classes)

Most applications that would benefit from a base Page or Control class (those with non-injectable existing pages) should use the AttributedInjectionModule described above.

If it is desired, however, dependency injection can be done in the Page_PreInit() handler in a base page class:

protected void Page_PreInit(object sender, EventArgs e)
{
  var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
  var cp = cpa.ContainerProvider;
  cp.RequestContainer.InjectProperties(this);
}

This approach is also worth considering if you have an application with a vast number of pages and only wish to apply dependency injection to a few of them.

Customising Dependency Injection Models

If the provided Property, Unset Property, and Attributed dependency injection models are unsuitable, it is very easy to create a customised injection behaviour. Simply subclass Autofac.Integration.Web.DependencyInjectionModule and use the result in Web.config.

There is one abstract member to implement:

protected abstract IInjectionBehaviour GetInjectionBehaviourForHandlerType(Type handlerType);

The returned IInjectionBehaviour can be one of the predefined NoInjection, PropertyInjection or UnsetPropertyInjection properties, or a custom implementation of the IInjectionBehaviour interface.

Status

The ASP.NET integration is available in the Autofac download archives.

Credits

Building this module was made much easier by this great article over at Geoff Lane's blog.


Comment by FREDERICK.Mao, Sep 28, 2008

This module requires that the HttpApplication? (Global Application Class) implements IContainerProviderAccessor. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Comment by brainunit, Oct 18, 2008

Here is my solution for This module requires that the HttpApplication?? (Global Application Class) implements IContainerProviderAccessor. exception:

  1. Create Global.cs file in the App_Code? directory and put there contents provided above (public class Global ...).
  2. Create Global.asax file in site root directory with following contents
  3. <%@ Application Inherits="Global" Language="C#" %>
  4. You can rename Global class or put it in the namespace, in this case you should update Inherits attribute in the Applicatin element of Global.asax file.

Best regards, Oleg Yaroshevych.

Comment by rationalpath, Jun 02, 2009

While this module will inject properties of ASP.NET controls (ascx), it can only do so if the control is created and added to the pages Controls collection by the PreLoad? step of the page request cycle. Controls created dynamically either in code, or through templates like the Repeater will not be visible at this point and must be injected manually.


Sign in to add a comment
Hosted by Google Code