com.alexey-developer89.Autofac2ZenjectLikeBridge
2.0.0
same package, but name is different, as well as id and namespace
+bugfixes
dotnet add package com.alexey-developer89.Autofac2ZenjectLikeBridge --version 2.0.0
NuGet\Install-Package com.alexey-developer89.Autofac2ZenjectLikeBridge -Version 2.0.0
<PackageReference Include="com.alexey-developer89.Autofac2ZenjectLikeBridge" Version="2.0.0" />
<PackageVersion Include="com.alexey-developer89.Autofac2ZenjectLikeBridge" Version="2.0.0" />
<PackageReference Include="com.alexey-developer89.Autofac2ZenjectLikeBridge" />
paket add com.alexey-developer89.Autofac2ZenjectLikeBridge --version 2.0.0
#r "nuget: com.alexey-developer89.Autofac2ZenjectLikeBridge, 2.0.0"
#:package com.alexey-developer89.Autofac2ZenjectLikeBridge@2.0.0
#addin nuget:?package=com.alexey-developer89.Autofac2ZenjectLikeBridge&version=2.0.0
#tool nuget:?package=com.alexey-developer89.Autofac2ZenjectLikeBridge&version=2.0.0
Autofac2ZenjectLikeBridge
Brings the power of Zenject's subcontainers syntax to Autofac, enabling Zenject-style dependency injection patterns in your Autofac applications. This library provides a familiar API for developers who love Zenject's approach to scoping and subcontainers but want to leverage Autofac's robust dependency injection capabilities.
đ Key Features
- Zenject-inspired subcontainer syntax for Autofac
- Subcontainer lifetime management
- Seamless integration of Zenject's scoping patterns
- Simplified decorator registration with isolated scopes
- Full compatibility with existing Autofac applications
IFactory<...>andPlaceholderFactory<...>for factory registration with subcontainer support
đĄ Why Use Autofac2ZenjectLikeBridge?
This library is ideal for:
- Teams transitioning from Zenject to Autofac
- Projects that want to combine the best of both DI containers
- Developers who prefer Zenject's subcontainer API but need Autofac's features
- Applications requiring advanced dependency injection scenarios with clean scoping
đĻ Installation
Install the package from NuGet:
Install-Package com.alexey-developer89.Autofac2ZenjectLikeBridge
Or via the .NET CLI:
dotnet add package com.alexey-developer89.Autofac2ZenjectLikeBridge
đ ī¸ Quick Start
// Create your container builder
var builder = new ContainerBuilder();
// Register your service from subcontainer
builder
.RegisterExtended<ISampleService>()
.FromSubScope()
.ByFunction(
subcontainerBuilder =>
{
// Register service in the subcontainer
// registered type should match type in RegisterFromSubScope
subcontainerBuilder
.RegisterType<SampleService>()
.As<ISampleService>()
.SingleInstance();
// Register dependencies in the subcontainer
// needed to run SampleService
subcontainerBuilder
.RegisterType<SampleDependency>()
.SingleInstance();
});
// ...
using var container = builder.Build();
container.Resolve<ISampleService>();
đ Documentation
âšī¸ Info: All instances resolved from subcontainers have to implement
IDisposableinterface. This needed to limit subcontainers lifetime. When instance is disposed, it's subcontainer will be disposed too. Instance'sDisposemethod will be called patched via Harmony library, more information here.
Creating Subcontainers
Create isolated subcontainers for instance. Based on Autofac's lifetime scope. Scope will inherit all dependencies from
parent scope(s). In the same time scope could have own dependencies, that will be available only in this scope.
See Quick Start for code sample.
When FromSubScope() called it supposed to create new nested ILifetimeScope register required type and all it dependencies and resolve that type form created subcontainer. In other words target type have to be registered in subcontainer installer and implements IDisposable
Overall structure
Type registration:
- from subScope:
-
IFactory<P0, P1, ... , PN, TInstance>
- from new instance
- from function
- from subScope:
PlaceholderFactory<P0, P1, ... , PN, TInstance>
- from new instance
- from function
- from subScope:
Modules
Autofac's modules could be used to register types in subcontainers. Module sample:
class SampleServiceModule : Module
{
private readonly object _data;
//pass all parameters to module's constructor as well as extra parameters or dependencies
//from parent DI container(s)
public SampleServiceModule(object data)
{
_data = data;
}
protected override void Load(ContainerBuilder builder)
{
//do ISampleService registration here
}
}
Simple registrations:
builder
.RegisterExtended<ISampleService>()
.FromSubScope()
.ByModule<SampleServiceModule>();
or even create module with using service provider. In that case module will be created in subcontainer and all dependencies from current scope will be available in the module.
builder
.RegisterExtended<ISampleService>()
.FromSubScope()
.ByModule<SampleServiceModule>((scope) => scope.CreateInstance<SampleServiceModule>(parameter));
Decorators
Simple
Autofac default:
builder
.RegisterDecorator<ServiceDecorator, IService>();
From Function
Use function to create decorator instance:
builder
.RegisterDecoratorExtended<ServiceDecorator, IService>()
.FromFunction(
(context, baseService) =>
{
var parameters = new Parameters();
return context.CreateInstance<ServiceDecorator>(baseService, parameters);
});
With Subcontainer
ByFunction
Use subcontainer to create decorator:
builder
.RegisterDecoratorExtended<ServiceDecorator, IService>()
.FromSubScope()
.ByFunction(
(subcontainerBuilder, baseService) =>
{
// Register service in the subcontainer
// registered type should match type in RegisterFromSubScope
subcontainerBuilder
.RegisterType<ServiceDecorator>()
.WithParameters(TypedParameter.From(baseService))
.SingleInstance();
// Register dependencies in the subcontainer
// needed to run ServiceDecorator
subcontainerBuilder
.RegisterType<SampleDependency>()
.SingleInstance();
});
By Module
As well instances could be created from module, decorator could also be created from module: In that case decoratable service will be passed to module constructor. Module sample:
class ServiceDecoratorModule : Module
{
private readonly object _data;
private readonly IService _service;
//pass all parameters and decoratable service to module's constructor as well as extra parameters or dependencies
//from parent DI container(s)
public ServiceDecoratorModule(IService service, object data)
{
_data = data;
_service = service;
}
protected override void Load(ContainerBuilder builder)
{
//do ServiceDecorator registration here
}
}
registration sample:
builder
.RegisterDecoratorExtended<ServiceDecorator, IService>()
.FromSubScope()
.ByModule<ServiceDecoratorModule>();
registration via service provider:
builder
.RegisterDecoratorExtended<ServiceDecorator, IService>()
.FromSubScope()
.ByModule((scope, service) => scope.CreateInstance<ServiceDecoratorModule>(service, parameter));
Factories
IFactory
Provides interface IFactory<parameter1, parameter2, ... , parameterN, Iinstance> where
parameter1, parameter2, ... , parameterN are parameters for factory creation and Iinstance is instance type.
From Functions
Use function to register IFactory<Iinstance> in DI:
builder
.RegisterIFactoryExtended<Iinstance>()
.FromFunction(
scope => new Instance
{
Data = Guid.NewGuid()
});
Use function to register IFactory<Guid, Iinstance> in DI:
builder
.RegisterIFactoryExtended<Guid, Iinstance>()
.FromFunction(
(scope, parameter) => new Instance
{
Data = parameter
});
From Subcontainers
Use subcontainer to create factory IFactory<Iinstance>, new subcontainer will be created when factory's Create
method is called:
By Function
builder
.RegisterIFactoryExtended<Iinstance>()
.FromSubScope()
.ByFunction(subcontainerBuilder =>
{
// Register service in the subcontainer
// registered type should match type in RegisterFactoryFromSubScope
subcontainerBuilder
.RegisterType<Iinstance>()
.SingleInstance();
// Register dependencies in the subcontainer
// needed to run Iinstance
subcontainerBuilder
.RegisterType<SampleDependency>()
.SingleInstance();
});
Parameters edition:
builder
.RegisterIFactoryExtended<Guid, Iinstance>()
.FromSubScope()
.ByFunction((subcontainerBuilder, parameter) =>
{
// Register service in the subcontainer
// registered type should match type in RegisterFactoryFromSubScope
subcontainerBuilder
.RegisterType<Iinstance>()
.WithParameters(TypedParameter.From(parameter))
.SingleInstance();
// Register dependencies in the subcontainer
// needed to run Iinstance
subcontainerBuilder
.RegisterType<SampleDependency>()
.SingleInstance();
});
By Module
Registration factories to resolve from module. All parameters will be passed to module's constructor. Module sample:
class ServiceModule : Module
{
private readonly string _data;
//pass all parameters to module's constructor as well as extra parameters or dependencies
//from parent DI container(s)
public ServiceModule(string data)
{
_data = data;
}
protected override void Load(ContainerBuilder builder)
{
//do IService registration here
}
}
Registration sample:
builder
.RegisterIFactoryExtended<string, IService>()
.FromSubScope()
.ByModule<ServiceModule>();
Registration sample with extra parameters via service provider:
builder
.RegisterIFactoryExtended<string, IService>()
.FromSubScope()
.ByModule<ServiceModule>(
(scope, arg3)
=> scope.CreateInstance<ServiceModule>(arg3, extraParameter));
Placeholders Factories
Used for registration of type distinct from interface IFactory<T>, and/or modify factory Create behavior, like some instance
initialization:
Create new class and inherit from PlaceholderFactory<T>:
class MyCustomFactory : PlaceholderFactory<Iinstance>
{
public MyCustomFactory(SomeDependency dependency)
{
//...
}
//you can override Create method
public override Iinstance Create()
{
return base.Create();
}
}
From Functions
Placeholders Factories registration is available from function:
builder
.RegisterPlaceholderFactoryExtended<Iinstance, MyCustomFactory>()
.FromFunction(
scope => new Instance
{
Data = Guid.NewGuid()
});
From Subcontainers
and for subcontainers, new subcontainer will be created and installer called to register all content in subcontainer
By Function
via function
builder
.RegisterPlaceholderFactoryExtended<
Guid,
Iinstance,
MyCustomFactory>()
.FromSubScope()
.ByFunction((subcontainerBuilder, parameter) =>
{
// Register service in the subcontainer
// registered type should match type in RegisterPlaceholderFactoryExtended
subcontainerBuilder
.RegisterType<Iinstance>()
.WithParameters(TypedParameter.From(parameter))
.SingleInstance();
// Register dependencies in the subcontainer
// needed to run Iinstance
subcontainerBuilder
.RegisterType<SampleDependency>()
.SingleInstance();
});
By Module
For module sample see by module section in IFactory registration.
The registration is similar to IFactory registration. And could reuse same modules.
Registration sample:
builder
.RegisterPlaceholderFactoryExtended<string, IService, MyCustomServiceFactory>()
.FromSubScope()
.ByModule<ServiceModule>();
Registration sample with extra parameters via service provider:
builder
.RegisterPlaceholderFactoryExtended<string, IService, MyCustomServiceFactory>()
.FromSubScope()
.ByModule<ServiceModule>(
(scope, arg3)
=> scope.CreateInstance<ServiceModule>(arg3, extraParameter));
where placeholder factory type is
class MyCustomServiceFactory : PlaceholderFactory<string, IService>
{
public MyCustomServiceFactory(SomeDependency dependency)
{
//...
}
//you can override Create method
public override IService Create(string arg)
{
return base.Create(arg);
}
}
Other Helpers
CompositeDisposable
Use CompositeDisposable for services and decorators to manage multiple disposables and comply with IDisposable and ICollection<IDisposable>. CompositeDisposable will dispose all disposables, added to it, when disposed.
Example:
var composite = new CompositeDisposable();
_disposable1.AddTo(composite);
_disposable2.AddTo(composite);
//_disposable1 & _disposable2 will be disposed here
composite.Dispose();
IComponentContext.CreateInstance
Use IComponentContext.CreateInstance to create instance of type with using DI container:
builder
.Register<SampleService>(context =>
{
var result = context.CreateInstance<SampleService>(Guid.NewGuid());
result.Setup();
return result;
})
.As<ISampleService>()
.SingleInstance();
HarmonyPatch Related
As mentioned before each instance resolved from subcontainer have to implement IDisposable interface. And subcontainer will be disposed when instance is disposed. To achieve this behavior HarmonyPatch is used.
It can add a finalizer to the instance A and set a reference to the instance B. When instance B will be disposed A will be disposed too.
That behavior is accessible via A.AddToHarmony(B) method. In that case B will be patched if not patched yet.
To force patch, in order to improve performance, use HarmonyPatch.EnsurePatched(typeof(B)) when program starts. Or use HarmonyPatch.PatchNonLazy() method to patch all types (in that case generic will not be patched).
đ¤ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
đ License
This project is licensed under the MIT License - see the LICENSE file for details.
đ Acknowledgments
- Inspired by Zenject's clean subcontainer API
- Built on top of Autofac's powerful DI container
- Thanks to all contributors who helped improve this project
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Autofac (>= 8.4.0)
- JetBrains.Annotations (>= 2025.2.1)
- Lib.Harmony (>= 2.4.1)
- Microsoft.Extensions.DependencyInjection (>= 9.0.8)
-
.NETStandard 2.1
- Autofac (>= 8.4.0)
- JetBrains.Annotations (>= 2025.2.1)
- Lib.Harmony (>= 2.4.1)
- Microsoft.Extensions.DependencyInjection (>= 9.0.8)
-
net6.0
- Autofac (>= 8.4.0)
- JetBrains.Annotations (>= 2025.2.1)
- Lib.Harmony (>= 2.4.1)
- Microsoft.Extensions.DependencyInjection (>= 9.0.8)
-
net8.0
- Autofac (>= 8.4.0)
- JetBrains.Annotations (>= 2025.2.1)
- Lib.Harmony (>= 2.4.1)
- Microsoft.Extensions.DependencyInjection (>= 9.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
version 2.0
simplified reqirements for subcontainer resolve
added builders
move from installers to Autofac's modules