qujck
qujck

Reputation: 14578

SimpleInjector Verification process with IIS Express / Visual Studio

I have a proprietary event model built into my solution that has a subscription instantiation process that uses the GetAllInstances() method of SimpleInjector to locate all of the subscribers of an event

public IEnumerable<ISubscriber<T>> GetSubscriptions<T>()
    where T : IEvent
{
    return _container.GetAllInstances<ISubscriber<T>>();
}

I am getting a massive difference in performance depending on whether I register all instances of ISubscriber or not

this is the code I use to register ISubscriber

internal void Configure(Container container)
{
    container.RegisterManyForOpenGeneric(
        typeof(ISubscriber<>),
        AccessibilityOption.PublicTypesOnly,
        (serviceType, implTypes) => 
            container.RegisterAll(serviceType, implTypes),
        AppDomain.CurrentDomain.GetAssemblies()
    );

    container.RegisterDecorator(typeof(ISubscriber<>), 
        typeof(SubscriberTraceDecorator<>));

    container.RegisterDecorator(typeof(ISubscriber<>), 
        typeof(SubscriberExceptionDecorator<>));
}

When I bootstrap the container without the call to RegisterManyForOpenGeneric the container verification takes around 11 seconds and returns the results:

Configuration Warnings: No warnings detected.

Registrations: Count = 158

However, when I uncomment the call to RegisterManyForOpenGeneric the container verification takes around 72 seconds and returns the results:

Configuration Warnings: 136 container-registered types have been detected that are referenced by 181 components

Registrations: Count = 475

My question is - is this ok or am I doing something wrong here? I am adding more ISubscriber classes all the time and start up is now (way) too slow ...


Update

It seems this is only an issue for a WebAPI project running inside Visual Studio. Bootstrapping from a Console Application takes 15 seconds running in Visual Studio. After deploying the WebAPI project to IIS the verification takes 6 seconds.

Upvotes: 3

Views: 309

Answers (1)

Steven
Steven

Reputation: 172826

Without a call to Verify(), the Simple Injector container will fallback to a sort of 'just in time' compilation of delegates during the time they are requested for the first time. In that case the container will often build a single delegate for the creation of a whole object graph (that 'root' object + all its direct and indirect dependencies). Since a delegate is built for a whole object graph there is often just a single delegate being compiled.

Compare that to calling the Container.Verify() method. When called, this method iterates over all registrations and requests an instance for each registration. This forces the compilation of a delegate for each registration in the container (not only for the root types that are requested directly).

In other words, there is a lot of overhead in calling Verify and all this generation and compilation is done at the start-up phase of your application, compared to the just-in-time like behavior you'd otherwise get.

Calling Verify() during start-up is not suited for each application. The time it takes for Verify() to complete depends on a lot of factors, such as:

  • The power of your machine.
  • Whether you're running inside the debugger or not.
  • The number of registrations in the container.
  • The use of special features. As you have noticed applying decorators can have impact on the compilation process. This especially holds when a decorator contains generic type constraints.

It is good to always call Verify() during start-up, until...

Until the configuration gets too big to call Verify(). In that case you can do the following:

  1. Prevent calling Verify when the debugger is attached, since the overhead is here the biggest.
  2. Prevent calling Verify during start-up in production if it takes too long for the application to start up.
  3. Create a unit test that calls into the bootstrapper code to request a configured container instance and let the unit test call Verify() on it. This ensures that configuration errors are still caught long before rolling the software out to test, acceptance or production. A verifiable configuration is very important.

Upvotes: 1

Related Questions