Autofac Web Forms 集成
ASP.NET Web Forms 集成需要使用 Autofac.Web NuGet 包。
Web Forms 集成提供了代码背后类的依赖注入集成。它还添加了 基于请求的生命周期支持。
此页面解释了 ASP.NET 经典 Web Forms 集成。 如果您正在使用 ASP.NET Core,请 查看 ASP.NET Core 集成页面 。
快速入门
要将 Autofac 与 Web Forms 集成,您需要引用 Web Forms 集成的 NuGet 包,并在 web.config
中添加模块,同时在 Global
应用类上实现 IContainerProviderAccessor
。
在 web.config
中添加模块:
<configuration>
<system.web>
<httpModules>
<!-- 这个部分用于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>
<!-- 这个部分用于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 通过使用 IHttpModule 实现来管理组件寿命并将其集成到 ASP.NET 管道中。您需要在 web.config
中配置这些模块。
以下片段显示了已配置的模块:
<configuration>
<system.web>
<httpModules>
<!-- 这个部分用于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>
<!-- 这个部分用于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,但强烈建议您同时使用这两个部分。ASP.NET 开发服务器即使目标部署环境是 IIS7 也会使用 IIS6 设置。如果您使用 IIS Express,它将使用 IIS7 设置。
您在那里看到的模块执行了一些有趣的操作:
- ContainerDisposalModule 让 Autofac 在请求完成后立即处理在请求处理期间创建的任何组件。
- PropertyInjectionModule 在页面生命周期执行之前将依赖项注入到页面中。还提供了替代的
UnsetPropertyInjectionModule
,它只会将 Web 表单/控件的属性设置为 null 值。 (仅使用一个或另一个,但不能两者都用。)
在 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());
然后,在页面的代码背后,为所需的依赖项创建公共的 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();
}
}
同样的公共属性注入过程也适用于用户控件,只需在应用程序启动时注册组件并为依赖项提供公共 get/set 属性即可。
重要的是要注意对于用户控件,只有当控件在页面请求生命周期的预加载阶段由页面创建并添加到 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
。两者之间的区别:
InjectPropertiesAttribute
将始终为页面/控件设置关联到 Autofac 注册的组件的公共属性。InjectUnsetPropertiesAttribute
只有当它们为 null 并且关联的组件已注册时,才会设置页面/控件的公共属性。
[InjectProperties]
public partial class MyPage : Page
{
// 这个属性将由 AttributedInjectionModule 自动设置。
public IService MyService { get; set; }
// ...根据需要稍后使用该属性。
}
通过基页面类进行依赖注入
如果你不想通过模块(例如之前提到的 AttributedInjectionModule
或 PropertyInjectionModule
)自动注入属性,可以以更手动的方式集成 Autofac,方法是创建一个在页面请求生命周期的 PreInit
阶段执行手动属性注入的基页面类。
如果只有少数页面需要依赖注入,这样做可能比较合适,而不需要在管道中包含 AttributedInjectionModule
(但仍然需要 ContainerDisposalModule
)。如果你有超过少量的页面,考虑通过属性进行显式注入可能是有益的。
protected void Page_PreInit(object sender, EventArgs e)
{
var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
var cp = cpa.ContainerProvider;
cp.RequestLifetime.InjectProperties(this);
}
定制依赖注入模块
如果提供的 属性、未设置属性 和 带有注解 的依赖注入模型不适合您的需求,创建自定义注入行为非常容易。只需继承 Autofac.Integration.Web.DependencyInjectionModule
,并在 Web.config
中使用结果即可。
要实现的一个抽象成员如下:
protected abstract IInjectionBehavior GetInjectionBehaviorForHandlerType(Type handlerType);
返回的 IInjectionBehavior
可以是预定义的 NoInjection
、PropertyInjection
或 UnsetPropertyInjection
属性之一;也可以是 IInjectionBehavior
接口的自定义实现。
示例
有关 ASP.NET Web 表单集成的示例项目,请参阅 Autofac 示例仓库。