|
AspNetIntegration
ASP.NET integration provides dependency injection for WebForms pages.
IntroductionIn 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 MVCThis wiki page covers generic integration and WebForms, for ASP.NET MVC see MvcIntegration. Typical ConfigurationReferenced AssembliesFor 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.configThe 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.asaxThe 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 ComponentsTo 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 ControlsPages 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 ConfigurationWhen 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 ModelsIf 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. StatusThe ASP.NET integration is available in the Autofac download archives. CreditsBuilding this module was made much easier by this great article over at Geoff Lane's blog. |
Sign in to add a comment
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.
Here is my solution for This module requires that the HttpApplication?? (Global Application Class) implements IContainerProviderAccessor. exception:
Best regards, Oleg Yaroshevych.
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.