Wiring up Simple Injector in WebForms in .NET 4.7.2

IMO, this new feature in Web Forms is not particularly well thought through. The main problem is that Web Forms breaks the IServiceProvider contract.

The IServiceProvider.GetService method defines that null should be returned if no such service exists. But once you actually return null, e.g. when you can’t construct that type, Web Forms throws a NullReferenceException from deep down its stack.

Would Web Forms, on the other hand, have conformed to the IServiceProvider abstraction, plugging in Simple Injector would have been a matter of a single statement, since SimpleInjector.Container actually implements IServiceProvider:

// WARNING: This won’t work
HttpRuntime.WebObjectActivator = container; 

On top of this, when an IServiceProvider is set through HttpRuntime.WebObjectActivator, Web Forms will call it for almost everything, even for its own internal objects, which, to me, makes little sense.

Therefore, instead of supplying an IServiceProvider implementation that is compatible to the IServiceProvider contract, you will have to provide a special ASP.NET Web Forms-compatible IServiceProvider implementation (which therefore breaks the contract).

Note that most DI Containers actually implement IServiceProvider, but you would see most of them fail, because of this contract breach.

An adapter implementation would look like this:

class SimpleInjectorWebFormsServiceActivator : IServiceProvider
{
    private const BindingFlags flag =
        BindingFlags.Instance | BindingFlags.NonPublic |
        BindingFlags.Public | BindingFlags.CreateInstance;

    private readonly Container container;

    public SimpleInjectorWebFormsServiceActivator(Container container) =>
        this.container = container;

    public object GetService(Type serviceType) =>
        serviceType.GetConstructors().Length > 0
            ? this.container.GetInstance(serviceType)
            : Activator.CreateInstance(serviceType, flag, null, null, null);
}

And can be set as follows:

HttpRuntime.WebObjectActivator =
    new SimpleInjectorWebFormsServiceActivator(container);

This implementation verifies whether the type contains public constructors and if so, it delegates the call to Simple Injector, which will construct the type. Otherwise, it will use Activator.CreateInstance to construct the type.

Do note that using this implementation you don’t need custom IConstructorSelectionBehavior, so you can remove your InternalConstructorResolutionBehavior altogether.