|
AspNetIntegration
ASP.NET integration provides dependency injection for web forms pages.
Autofac2 Types of ASP.NET ApplicationsIn recent versions of ASP.NET you have a few options. Pending on how you choose to construct your site, Autofac offers different integration techniques.
Standard IntegrationIn order to integrate Autofac with ASP.NET in the most common fashion, you'll need to...
Once you've done those things, a standard ASP.NET web forms application will be ready to go. If you're using ASP.NET MVC2 you still need to do all of this, but there are a few additional steps. Reference AssembliesAdd references from your ASP.NET application to the following assemblies...
If you are using ASP.NET MVC2, you'll also need to reference Autofac.Integration.Web.Mvc.dll. Add Modules to Web.configThe way that Autofac manages component lifetimes and adds dependency injection into the ASP.NET pipeline is through the use of IHttpModule implementations. You need to configure these modules in web.config. The following snippet config shows the modules configured. <configuration>
<system.web>
<httpModules>
<!-- This section is used for IIS6 -->
<add
name="ContainerDisposal"
type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web"/>
<add
name="PropertyInjection"
type="Autofac.Integration.Web.Forms.PropertyInjectionModule, Autofac.Integration.Web"/>
</httpModules>
</system.web>
<system.webServer>
<!-- This section is used for IIS7 -->
<modules>
<add
name="ContainerDisposal"
type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web"
preCondition="managedHandler"/>
<add
name="PropertyInjection"
type="Autofac.Integration.Web.Forms.PropertyInjectionModule, Autofac.Integration.Web"
preCondition="managedHandler"/>
</modules>
</system.webServer>
</configuration>Note that while there are two different sections the modules appear in - one each for IIS6 and IIS7 - it is recommended that you have both in place. The ASP.NET Developer Server ("Cassini") uses the IIS6 settings even if your target deployment environment is IIS7. The modules you see there do some interesting things:
For ASP.NET MVC2 the PropertyInjectionModule is optional. While it won't hurt to have it there, ASP.NET MVC hooks up in a different way (see MvcIntegration) so in a pure MVC site this won't get you property injection. That said, if you have a web forms site (or an MVC/web forms mix) then you need to have the PropertyInjectionModule in place. Implement IContainerProviderAccessor in 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
{
// Provider that holds the application container.
static IContainerProvider _containerProvider;
// Instance property that will be used by Autofac HttpModules
// to resolve and inject dependencies.
public IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}
protected void Application_Start(object sender, EventArgs e)
{
// Build up your application container and register your dependencies.
var builder = new ContainerBuilder();
builder.RegisterType<SomeDependency>();
// ... continue registering dependencies...
// Once you're done registering things, set the container
// provider up with your registrations.
_containerProvider = new ContainerProvider(builder.Build());
}
}Autofac.Integration.Web.IContainerProvider exposes two useful properties: ApplicationContainer and RequestLifetime.
Web Forms Integration CompleteFor a web forms application, the above steps are all you need to do. The rest of this document will explain some additional/advanced usage scenarios. If you're using ASP.NET MVC2 there are a few additional integration steps. Component LifetimesWhen you register components for injection, you have the standard set of instance scopes to work with: per dependency, single instance, or per lifetime scope. ASP.NET integration adds a special component lifetime that allows a component instance to live for the life of a single HTTP request. You can register components using the "HttpRequestScoped()" extension method in the Autofac.Integration.Web namespace: var builder = new ContainerBuilder(); builder.RegisterType<Foo>().As<IFoo>().HttpRequestScoped(); Manual Dependency ResolutionIn some cases, like in programmatic creation of user controls or other objects, you may need to manually inject properties on an object. To do this, you need to:
In code, that looks like this: var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance; var cp = cpa.ContainerProvider; cp.RequestLifetime.InjectProperties(objectToSet); Web Forms Tips and TricksThere are some specific techniques and tips you can take advantage of when working with ASP.NET web forms. For MVC2 tips, see the ASP.NET MVC2 integration page. Implementing Web Forms Pages and User ControlsIn order to inject dependencies into web forms pages (System.Web.UI.Page instances) or user controls (System.Web.UI.UserControl instances) you must expose their dependencies as public properties that allow setting. This enables the PropertyInjectionModule (as seen earlier) to populate those properties for you. Be sure to register the dependencies you'll need at application startup (as seen in the IContainerProviderAccessor implementation above)... var builder = new ContainerBuilder(); builder.RegisterType<Foo>().As<IFoo>().HttpRequestScoped(); // ... continue registering dependencies and then build the // container provider... _containerProvider = new ContainerProvider(builder.Build()); Then in your page codebehind, create public get/set properties for the dependencies you'll need: // MyPage.aspx.cs
public partial class MyPage : Page
{
// This property will be set for you by the PropertyInjectionModule.
public IFoo SomeDependency { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
// Now you can use the property that was set for you.
label1.Text = this.SomeDependency.SomeMessage;
}
}This same process of public property injection will work for user controls, too - just register the components at application startup and provide public get/set properties for the dependencies. It is important to note in the case of user controls that properties will only be automatically injected if the control is created and added to the page's Controls collection by the PreLoad step of the page request lifecycle. Controls created dynamically either in code or through templates like the Repeater will not be visible at this point and must have their dependencies manually resolved. Explicit Injection via AttributesWhen adding dependency injection to an existing application, it is sometimes desirable to distinguish between web forms 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. If you choose to use the AttributedInjectionModule, no dependencies will be automatically injected into public properties unless they're marked with a special attribute. First, remove the PropertyInjectionModule from your web.config file and replace it with the AttributedInjectionModule: <configuration>
<system.web>
<httpModules>
<!-- This section is used for IIS6 -->
<add
name="ContainerDisposal"
type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web"/>
<add
name="AttributedInjection"
type="Autofac.Integration.Web.Forms.AttributedInjectionModule, Autofac.Integration.Web"/>
</httpModules>
</system.web>
<system.webServer>
<!-- This section is used for IIS7 -->
<modules>
<add
name="ContainerDisposal"
type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web"
preCondition="managedHandler"/>
<add
name="AttributedInjection"
type="Autofac.Integration.Web.Forms.AttributedInjectionModule, Autofac.Integration.Web"
preCondition="managedHandler"/>
</modules>
</system.webServer>
</configuration>Once this is in place, pages and controls will not have their dependencies injected by default. Instead, they must be marked with the Autofac.Integration.Web.Forms.InjectPropertiesAttribute or Autofac.Integration.Web.Forms.InjectUnsetPropertiesAttribute. The difference:
[InjectProperties]
public partial class MyPage : Page
{
// This property will be set for you by the AttributedInjectionModule.
public IFoo SomeDependency { get; set; }
// ...use the property later as needed.
}Dependency Injection via Base Page ClassIf you would rather not automatically inject properties using a module (e.g., the AttributedInjectionModule or PropertyInjectionModule as mentioned earlier), you can integrate Autofac in a more manual manner by creating a base page class that does manual dependency resolution during the PreInit phase of the page request lifecycle. This option allows you to derive pages that require dependency injection from a common base page class. Doing this may be desirable if you have only a very few pages that require dependency injection and you don't want the AttributedInjectionModule in the pipeline. (You still need the ContainerDisposalModule.) If you have more than a small few pages it may be beneficial to consider explicit injection via attributes. protected void Page_PreInit(object sender, EventArgs e)
{
var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
var cp = cpa.ContainerProvider;
cp.RequestLifetime.InjectProperties(this);
}Creating a Custom Dependency Injection ModelsIf the provided Property, Unset Property, and Attributed dependency injection models are unsuitable, it is very easy to create a custom injection behavior. 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. Additional ResourcesBuilding this module was made much easier by this great article over at Geoff Lane's blog. | |
I think in version 2.2 HttpRequestScoped? is replaced by InstancePerHttpRequest? which is equivalent to InstancePerLifetimeScope?, is it not? It would be nice if this documentation is updated to refelct these API changes.
Looks like the manual dependency injection api has changed. InjectProperties? doesn't exist. What is the proper way now?