This library is an extension to Ninject, providing a way to define ambient scopes. An ambient scope is a logical container for objects that are shared during the lifetime of an ambient transaction. The ambient scope provides deterministic disposal of objects, ensuring proper cleanup and resource management. This library makes it easier to manage scoped dependencies in your application when using Ninject for dependency injection.
To install the package, you can reference it directly from your project.
-
Initialize Kernel with Ambient Scopes
var kernel = new StandardKernel(); kernel.LoadAmbientScopeModule();
-
Bind Services with Ambient Scope
kernel.Bind<MyService>().ToSelf().InAmbientScope();
-
Begin a New Ambient Scope
using (kernel.BeginAmbientScope()) { // Your code here var myService = kernel.Get<MyService>(); // ... } // myService will be disposed here.
In addition to the core implementation, this project also provides an adapter for the IServiceScopeFactory interface from Microsoft's Dependency Injection package.
By utilizing this adapter, you can seamlessly integrate the benefits of ambient scopes without directly referencing the specific Ninject implementation.
Instead, you can inject the standard IServiceScopeFactory into your classes, allowing for a consistent and portable approach to managing object lifecycles across different contexts.
public class MyService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public MyService(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}
public void DoWork()
{
using (var scope = _serviceScopeFactory.CreateScope())
{
var scopedServiceProvider = scope.ServiceProvider;
var myScopedInstance = scopedServiceProvider.GetService<ScopedService>();
// Use myScopedInstance...
}
// The scoped resources are disposed when the scope is exited.
}
}You can nest ambient scopes, each new scope will be isolated from the others.
using (var outerScope = kernel.BeginAmbientScope())
{
// Kernel will resolve ambient objects using outerScope
// Nested scope
using (var innerScope = kernel.BeginAmbientScope())
{
// Kernel will resolve ambient objects using innerScope
}
}-
Scope Isolation Across Tasks and Threads
Ambient scopes created in different tasks (or threads) are isolated. Each task or thread will have its own scope, even if they are part of the same parent scope.
using (kernel.BeginAmbientScope()) { // Task 1 await Task.Run(() => { var nestedScope1 = kernel.BeginAmbientScope(); // This will be isolated from the parent and sibling scopes }); // Task 2 await Task.Run(() => { var nestedScope2 = kernel.BeginAmbientScope(); // This will also be isolated from the parent and sibling scopes }); }
-
Scope Inheritance from Parent Task to Child Tasks
When you start a new child task using
Task.Run()or create a new thread usingThread.Start(), the child task or thread will inherit the ambient scope from its parent.using (kernel.BeginAmbientScope()) { // The following child tasks will inherit the current ambient scope await Task.Run(() => { // This task will have access to the ambient scope defined above }); await Task.Run(() => { // This task will also have access to the ambient scope defined above }); }
This library comes with a comprehensive set of unit tests. To run them, either use Visual Studio Test Explorer or navigate to the root directory and execute the test runner:
dotnet testFeel free to review the code, make pull requests, or suggestions. Thanks for reading !