Reputation: 14578
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
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:
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:
Verify
when the debugger is attached, since the overhead is here the biggest.Verify
during start-up in production if it takes too long for the application to start up.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