使用 WebForms 的简单注入器

Simple Injector with WebForms

背景

我正在帮助另一位开发人员组装一个演示应用程序作为创建测试的典型代表,使用 DI 容器、项目结构和其他可以提高代码质量的东西,同时希望我们能够更快地发布更多可用的软件。

在此演示中,我想使用 Simple Injector。我已经按照他们文档中的 integration guide 来获取其中的 DI 部分和 运行。我遇到的障碍是在启动网站时。我收到此错误。

The configuration is invalid. The following diagnostic warnings were reported: -[Disposable Transient Component] _Default is registered as transient, but implements IDisposable. See the Error property for detailed information about the warnings. Please see https://simpleinjector.org/diagnostics how to fix problems and how to suppress individual warnings.

这是网络表单的隐藏代码

Public Class _Default
    Inherits System.Web.UI.Page

    <Import>
    Public Property TrueService As ITrueService

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        lbl.Text = TrueService.ReturnsTrue().ToString()
    End Sub

End Class

这是我在应用程序启动时调用的方法。

Private Shared Sub Bootstrap()
    ' 1. Create a new Simple Injector container.
    Dim container = New Container()
    container.Options.DefaultScopedLifestyle = new WebRequestLifestyle()

    ' Register a custom PropertySelectionBehavior to enable property injection.
    container.Options.PropertySelectionBehavior = New ImportAttributePropertySelectionBehavior()

    ' 2. Configure the container (register)
    container.Register(Of ITrueRepository, TrueRepository)(Lifestyle.Scoped)
    container.Register(Of ITrueService, TrueService)(Lifestyle.Scoped)

    ' Register your Page classes.
    RegisterWebPages(container)

    ' 3. Store the container for use by Page classes.
    _container = container

    ' 4. Optionally verify the container's configuration.
    '    Did you know the container can diagnose your configuration?
    '    For more information, go to: https://simpleinjector.org/diagnostics.
    container.Verify()
End Sub

在container.Verify()中抛出异常。在设置和不设置 DefaultScopedLifestyle 的情况下,我都试过了。 Global.asax 中的其他所有内容都与他们的文档中给出的内容相同。

根据给出的错误消息,我是否应该在需要 属性 注入的页面上注册?我认为这是通过 <Import> 属性解决的。

编辑:澄清一下,我正在使用一个 Web 应用程序项目执行此操作,因为我们计划很快转向该项目。

EDIT2:@Steven 的回答让魔法发生并加载了页面。不幸的是,页面在浏览器中完成呈现后 ASP.NET 触发了另一系列事件,我看到了这个错误:

An exception of type 'SimpleInjector.ActivationException' occurred in SimpleInjector.dll but was not handled in user code

No registration for type RequestDataHttpHandler could be found and an implicit registration could not be made. The constructor of type RequestDataHttpHandler contains parameter 'requestId' of type String which can not be used for constructor injection.

使用此堆栈跟踪:

at SimpleInjector.Container.ThrowNotConstructableException(Type concreteType)
at SimpleInjector.Container.ThrowMissingInstanceProducerException(Type serviceType)
at SimpleInjector.Container.ThrowInvalidRegistrationException(Type serviceType, InstanceProducer producer)
at SimpleInjector.Container.GetRegistration(Type serviceType, Boolean throwOnFailure)
at DITest.UI.Application.GlobalAsax.InitializeHandler(IHttpHandler handler) in C:\Users\slmartin\Documents\Visual Studio 2015\Projects\DITest\DITest.UI.Application\Global.asax.vb:line 41
at DITest.UI.Application.PageInitializerModule._Closure$__2-0._Lambda$__0(Object sender, EventArgs e) in C:\Users\slmartin\Documents\Visual Studio 2015\Projects\DITest\DITest.UI.Application\Global.asax.vb:line 26
at DITest.UI.Application.PageInitializerModule._Closure$__2-0._Lambda$__R1(Object a0, EventArgs a1)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

这发生在这个方法中,它是从 PageInitializerModule 中的 Init 方法调用的:

Public Shared Sub InitializeHandler(handler As IHttpHandler)
    _container.GetRegistration(handler.GetType(), True).Registration.InitializeInstance(handler)
End Sub

自 Simple Injector v3 以来,容器现在在验证配置的正确性方面更加严格。当调用 Verify 时,诊断为 运行 并且当您的配置出现问题时会抛出异常。虽然这是一个很好的改变,但它是一个破坏性的改变。

很遗憾,我们忘记在发布期间更新 Web 表单的集成指南。您必须将 RegisterWebPages 方法更改为以下内容(请原谅我的 C#):

private static void RegisterWebPages(Container container)
{
    var pageTypes =
        from assembly in BuildManager.GetReferencedAssemblies().Cast<Assembly>()
        where !assembly.IsDynamic
        where !assembly.GlobalAssemblyCache
        from type in assembly.GetExportedTypes()
        where type.IsSubclassOf(typeof(Page))
        where !type.IsAbstract && !type.IsGenericType
        select type;

    foreach (Type type in pageTypes)
    {
        var registration = Lifestyle.Transient.CreateRegistration(type, container);
        registration.SuppressDiagnosticWarning(
            DiagnosticType.DisposableTransientComponent,
            "ASP.NET creates and disposes page classes for us.");
        container.AddRegistration(type, registration);
    }
}

我们将相应地更新集成指南。

请参阅the documentation了解如何与最新版本的 Simple Injector 集成。