Simple .NET dependency injection framework based on emitting IL code at service registration time.
PM> Install-Package Photosphere.DependencyInjection
- Fast resolving
- Preferred declarative style
- Facilitate low coupling
- Registering all descendants by common interface
- Type registration by attribute on base type
- Object graph analysis performed at registration time
- Control over objects life
- Easy to use
- Collections injecting
- Generic registration
- Integrations
This container based on building dynamic methods (using System.Reflection.Emit
) for every registered service. It is very speeds up the resolving of dependencies when requested.
Container must be configured in a composition root of project/assembly.
internal class CompositionRoot : ICompositionRoot
{
public void Compose(IRegistrator registrator)
{
registrator
.Register<IFoo>()
.Register<IBar>();
}
}
You can hint composition root type for more faster container initialization
[assembly: CompositionRoot(typeof(FooCompositionRoot))]
Light container setup directly into attributes (instead CompositionRoot
)
[assembly: RegisterDependencies(typeof(IService))]
[assembly: RegisterDependencies(typeof(IFoo), Lifetime.AlwaysNew)]
These methods of registration are resolved as follows:
- at the first container try to search
CompositionRootAttribute
and use it; - if it wasn't founded, container try to get up registration info from
RegisterDependenciesAttribute
andRegisterDependenciesByAttribute
; - if these attributes wasn't founded the whole-types-search for
ICompositionRoot
implementations will be performed.
Service can be registered just by interface: search of implementation is carried out in the registration process. It reduce horrible registration mappings that bring only redundant references through a code.
Just use Register<TService>
method:
registrator.Register<IFoo>();
registrator.Register<IBar>();
for register implementations of IFoo
and IBar
.
interface IService {}
interface IFoo : IService{}
class Foo : IFoo {}
interface IBar : IService {}
class Bar : IBar
{
public Bar(IFoo foo) {}
}
registrator.Register<IService>();
var foo = registrator.GetInstance<IFoo>();
var bar = registrator.GetInstance<Bar>();
If you don't want to register by interface or base type you can use your own custom attribute for it.
class ServiceAttribute : Attribute {}
[Service]
class Foo {}
class Bar : Foo {}
Registration
registrator.RegisterBy<ServiceAttribute>();
or
[assembly: RegisterDependenciesBy(typeof(ServiceAttribute))]
Providing
var foo = container.GetInstance<Foo>();
var bar = container.GetInstance<Bar>();
This attribute can be applyed to interfaces too.
Detects and denies cycles and not registered dependencies while service registration.
class Foo { public Foo(Bar bar) {} }
class Bar { public Bar(Buz buz) {} }
class Buz { public Buz(Foo foo) {} }
Provides three strategies of managing of lifetime: services can be always created anew, lives only during the time of the request or has container bounded life. Not uber feature :)
Register:
internal class CompositionRoot : ICompositionRoot
{
public void Compose(IRegistrator registrator)
{
registrator
.Register<IFoo>()
.Register<IBar>(Lifetime.AlwaysNew)
.Register<IBuz>(Lifetime.PerRequest)
.Register<IQiz>(Lifetime.PerContainer);
}
}
...and resolve:
var container = new DependencyContainer();
var foo = container.GetInstance<IFoo>();
foo.DoSomething();
var foos = container.GetInstance<IEnumerable<IFoo>>();
or
var foos = container.GetAllInstances<IFoo>();
or
class Bar
{
public Bar(IEnumerable<IFoo> foos) {}
}
Instead IEnumerable
can be used IReadOnlyCollection
that can be preffered for more clean OOP style.
You can register generic service
registrator.Register(typeof(IGenericService<>))
and receive constructed type
var foo = container.GetInstance<IGenericService<IFoo>>();
or receive multiple constructed type
var bars = container.GetAllInstances<IGenericService<Bar>>();