ASP.NET Web表单集成需要Autofac.Web
NuGet包。
Web表单集成为code-behind类提供了依赖注入集成。 它也增加了每个请求生命周期的支持。
本页面介绍了ASP.NET经典的Web表单集成。 如果您正在使用ASP.NET Core
,请参阅ASP.NET Core
集成页面。
Quick Start
Add Modules to Web.config
Implement IContainerProviderAccessor in Global.asax
Tips and Tricks
Structuring Pages and User Controls for DI
Manual Property Injection
Explicit Injection via Attributes
Dependency Injection via Base Page Class
Custom Dependency Injection Modules
Example
快速开始
要将Autofac
与Web表单集成,您需要引用Web表单集成NuGet包,将模块添加到web.config
,并在您的全局应用程序类上实现IContainerProviderAccessor
。
将模块添加到web.config中:
<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>
实现IContainerProviderAccessor
:
public class Global : HttpApplication, IContainerProviderAccessor
{
// 持有应用程序容器的提供程序
static IContainerProvider _containerProvider;
//将被`Autofac HttpModules`用来解析和注入依赖关系的实例属性。
public IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}
protected void Application_Start(object sender, EventArgs e)
{
//建立您的应用程序容器并注册您的依赖关系
var builder = new ContainerBuilder();
builder.RegisterType<SomeDependency>();
// ...继续注册依赖关系...
//完成注册之后,请将注册设置为容器提供者
_containerProvider = new ContainerProvider(builder.Build());
}
}
以下各节详细介绍了每个功能的用途以及如何使用它们。
将模块添加到Web.config
Autofac管理组件生命周期的方式和向ASP.NET管道中添加依赖注入的方式是通过使用IHttpModule
实现。 您需要在web.config
中配置这些模块。
以下片段配置显示配置的模块。
<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>
请注意,尽管有两个不同的部分,模块出现在IIS6和IIS7中,但建议您同时使用这两个部分。 即使您的目标部署环境是IIS7,ASP.NET开发人员服务器也会使用IIS6设置。 如果使用IIS Express,它将使用IIS7设置。
你在那里看到的模块做了一些有趣的事情:
ContainerDisposalModule
让Autofac处理请求处理期间创建的任何组件,只要请求完成。- 在页面生命周期执行之前,
PropertyInjectionModule
将依赖注入到页面中。还提供了一个替代的UnsetPropertyInjectionModule
,它只会在具有空值的Web表单/控件
上设置属性。(只使用一个或另一个,但不能同时使用)
在Global.asax中实现IContainerProviderAccessor
依赖注入模块期望HttpApplication
实例支持IContainerProviderAccessor
。下面显示了一个完整的全局应用程序类:
public class Global : HttpApplication, IContainerProviderAccessor
{
//持有应用程序容器的提供程序
static IContainerProvider _containerProvider;
//将被Autofac HttpModules用来解析和注入依赖关系的实例属性。
public IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}
protected void Application_Start(object sender, EventArgs e)
{
//建立您的应用程序容器并注册您的依赖关系
var builder = new ContainerBuilder();
builder.RegisterType<SomeDependency>();
// ...继续注册依赖关系...
//完成注册之后,请将注册设置为容器提供商
_containerProvider = new ContainerProvider(builder.Build());
}
}
Autofac.Integration.Web.IContainerProvider
公开了两个有用的属性:ApplicationContainer
和RequestLifetime
。
ApplicationContainer
是在应用程序启动时构建的根容器。RequestLifetime
是基于应用程序容器的组件生命周期作用域,它将在当前Web请求的末尾处理。只要需要手动依赖关系解析/服务查找,就可以使用它。它包含的组件(除了任何单例)将特定于当前请求(这是每个请求生命周期依赖性被解决的地方)。
技巧和窍门
为DI构建页面和用户控件
为了向Web表单页面(System.Web.UI.Page
实例)或用户控件(System.Web.UI.UserControl
实例)注入依赖项,必须将其依赖项公开为允许设置的公共属性。这使PropertyInjectionModule
为您填充这些属性。
确保在应用程序启动时注册您将需要的依赖关系。
var builder = new ContainerBuilder();
builder.RegisterType<Component>().As<IService>().InstancePerRequest();
//...继续注册依赖关系,然后构建容器提供者...
_containerProvider = new ContainerProvider(builder.Build());
然后在你的页面代码隐藏中,为你需要的依赖项创建public get/set
属性:
// MyPage.aspx.cs
public partial class MyPage : Page
{
//该属性将由PropertyInjectionModule为您设置
public IService MyService { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
//现在您可以使用为您设置的属性
label1.Text = this.MyService.GetMessage();
}
}
同样的公共属性注入过程也适用于用户控件 - 只需在应用程序启动时注册组件,并为依赖关系public get/set
属性。
在用户控件的情况下,必须注意,如果通过页面请求生命周期的PreLoad
步骤创建控件并将其添加到页面的Controls
集合,那么只会自动注入属性。在代码中或通过像Repeater
这样的模板动态创建的控件在此处将不可见,并且必须手动注入其属性。
手动属性注入
在某些情况下,如在编程创建用户控件或其他对象时,可能需要手动在对象上注入属性。要做到这一点,你需要:
- 获取当前的应用程序实例。
- 将其转换为
Autofac.Integration.Web.IContainerProviderAccessor
。 - 从应用程序实例中获取容器提供者。
- 从
IContainerProvider
获取RequestLifetime
,并使用InjectProperties()
方法在对象上注入属性。
在代码中,看起来像这样:
var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
var cp = cpa.ContainerProvider;
cp.RequestLifetime.InjectProperties(objectToSet);
请注意,您需要Autofac
和Autofac.Integration.Web
名称空间来使属性注入工作,因为InjectProperties()
是Autofac
名称空间中的扩展方法。
通过属性显式注入
当向现有应用程序添加依赖项注入时,有时需要区分将注入依赖关系的注入和不注入的Web表单页面。 Autofac.Integration.Web
中的InjectPropertiesAttribute
与AttributedInjectionModule
一起帮助实现了这一点。
如果您选择使用AttributedInjectionModule
,则不会自动将依赖项注入到公共属性中,除非它们被标记为特殊属性。
首先,从web.config
文件中移除PropertyInjectionModule
,并将其替换为AttributedInjectionModule
:
<configuration>
<system.web>
<httpModules>
<!--本部分用于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>
<!--本部分用于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>
一旦到位,页面和控件将不会默认注入其依赖项。 相反,它们必须用Autofac.Integration.Web.Forms.InjectPropertiesAttribute
或Autofac.Integration.Web.Forms.InjectUnsetPropertiesAttribute
标记。 区别:
- 如果在Autofac中注册了相关的组件,
InjectPropertiesAttribute
将始终在页面/控件上设置公共属性。 InjectUnsetPropertiesAttribute
只会设置页面/控件上的公共属性,如果它们为空,并且关联的组件被注册。
[InjectProperties]
public partial class MyPage : Page
{
//该属性将由AttributedInjectionModule为您设置
public IService MyService { get; set; }
// ...稍后根据需要使用该属性.
}
通过基本页面类的依赖注入
如果您不想使用模块自动注入属性(例如前面提到的AttributedInjectionModule
或PropertyInjectionModule
),则可以通过创建一个在页面的PreInit
阶段执行手动属性注入的基本页类,以更人工的方式集成Autofac 请求生命周期。
这个选项允许你从一个普通的基本页面类派生需要依赖注入的页面。 如果只有很少的页面需要依赖注入,并且不需要管道中的AttributedInjectionModule
,则可能需要执行此操作。 (您仍然需要ContainerDisposalModule
。)如果您的页面少于几页,则可以考虑通过属性显式注入。
protected void Page_PreInit(object sender, EventArgs e)
{
var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
var cp = cpa.ContainerProvider;
cp.RequestLifetime.InjectProperties(this);
}
自定义依赖注入模块
如果提供的Property
,Unset Property
和Attributed
依赖注入模型不合适,那么创建自定义注入行为是非常容易的。 简单地继承Autofac.Integration.Web.DependencyInjectionModule
并在Web.config
中使用结果。
有一个抽象成员来实现:
protected abstract IInjectionBehaviour GetInjectionBehaviourForHandlerType(Type handlerType);
返回的IInjectionBehaviour
可以是预定义的NoInjection
,PropertyInjection
或UnsetPropertyInjection
属性之一; 或IInjectionBehaviour
接口的自定义实现。
示例
有一个示例项目显示了Autofac示例存储库中的ASP.NET Web表单集成。