I have an Azure WebJob containing few different functions.
These functions need to be injected with some services by Ninject (using constructor injection). Since the standard JobActivator - the class which is responsible to instantiate jobs' classes - creates them by invoking a parameterless costructor, I cannot use that.
In order to do this, I've created a class implementing the IJobActivator interface - provided by the WebJobs SDK, following something similar to this walkthrough.
Since I need this injected services to be alive until the function completes (and it seems that there is no way for the container to know when a function completes), I followed this workaround: https://blog.tech-fellow.net/2017/04/12/disposable-dependency-for-azure-webjob/
That article refers to a different container (StructureMap), but the concept is the same:
- inside the
JobActivatora nested container is created - that nested container is passed to the class that contains the function
- the class that contains the function implements
IDisposableinterface - inside the
Dispose()method that child container is disposed
Ninject, as far as I know, doesn't support nested containers, even if I found this extension that seems to do something similar.
So what I would do is:
- create a main kernel inside the WebJob, which I pass to the
JobActivator - inside the
CreateInstanceof theJobActivator, I create a new Child Kernel, from the original one - I set that child kernel into the job's class instance
- inside the
Disposemethod, I will dispose the child kernel
Questions:
- what do you think about this approach of creating child kernels? Is something that you would avoid?
- by checking the source code of the Child Kernel extension, it seems to me that, there is no particular change on the
Disposemethod of the child kernel. Am I correct if I say that by callingDispose()on the child kernel, wont' dispose the main one? - can you please confirm that as soon as a Ninject kernel il disposed (by calling its
Dispose()method), then all the created instances - even those that are InTransientScope - will be disposed?
It turns out that creating a
ChildKernelinside theJobActivatorActivate()function is a very slow process.My analysis shows that, if the concurrency on the
JobActivatoris high, the process of spinning up a new ChildKernel and activate the job will take a considerable amount of time. In my case it was a magnitude of order greater that the real job execution time, so it was totally unceptable.What I did is serialize the process of job creation inside the
JobActivator, by scoping to a particularExecutionContext(a class that I created) the services that I needed to be scoped to a particular function execution.All of my jobs implements the
IDisposableinterface. In the correspondingDispose()method, I will dispose that particularExecutionContext, letting Ninject Kernel (the only one instantiated inside the Program.cs) finally release services scoped to that object.