1

Background

I'm helping another developer put together a demo application as a poster child for creating tests, using a DI Container, project structure and other things that will increase code quality while hopefully allowing us to release more usable software faster.

In this demo I want to use Simple Injector. I've followed the integration guide on their docs to get the DI portion of this up and running. The snag I've hit is when getting the site to launch. I get this error.

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.

Here is the code behind for the webform

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

And here is the method I call in the application start.

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

The exception is thrown in container.Verify(). I have tried this with and without setting the DefaultScopedLifestyle. Everything else in the Global.asax is the same as what's given in their docs.

Based on the error message given, am I supposed to register the pages where I need the property injection? I thought this was taken care of with the <Import> attribute.

EDIT: To clarify I am doing this with a web application project as we plan to move to that soon.

EDIT2: @Steven's answer lets the magic happen and the page loads. Unfortunately after the page finishes rendering in the browser ASP.NET fires off another series of events and I see this error:

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.

With this stack trace:

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)

This happens in this method, which is called from the Init method in the PageInitializerModule:

Public Shared Sub InitializeHandler(handler As IHttpHandler)
    _container.GetRegistration(handler.GetType(), True).Registration.InitializeInstance(handler)
End Sub
Slowbad
  • 65
  • 2
  • 8

1 Answers1

2

Since Simple Injector v3, the container is now much stricter in verifying the correctness of your configuration. When Verify is called, the diagnostics are ran and an exception is thrown when there is a problem with your configuration. Although this is a very good change, it is a breaking change.

Unfortunately, we forgot to update the integration guide for web forms during the release. You will have to change the RegisterWebPages method to the following (excuse my C#) the following:

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);
    }
}

We will update the integration guide accordingly.

Please see the documentation to see how to integrate with the latest version of Simple Injector.

Steven
  • 166,672
  • 24
  • 332
  • 435
  • This answers my question but I'm now running into another problem. I'm getting an exception when Global.InitializeHandler is getting called from the PageInitializerModule. The page will load and display but this gets called after. `Additional information: 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.` – Slowbad Oct 22 '15 at 13:00
  • @Slowbad: Please update your question and add the full stacktrace\. – Steven Oct 22 '15 at 13:03
  • @Slowbad: Is this `RequestDataHttpHandler` something you defined? Where is that handler coming from? – Steven Oct 22 '15 at 14:06
  • I did not create that class. Cursory google search reveals this is something from Visual Studio, `Microsoft.VisualStudio.Web.PageInspector.Runtime`. I found a link to the [Simple Injector discussion boards](http://simpleinjector.codeplex.com/discussions/568084). that tries to solve a similar problem but I don't know how much is specific to MVC. – Slowbad Oct 22 '15 at 14:25
  • The easiest way for you is to let the InitializeHandler method skip this specific handler type. In fact the MVC integration package contain a more durable approach, but this is a bit more work. – Steven Oct 22 '15 at 15:03