Content
Advanced features
Container injection
Dependency injection cannot be used everywhere, and it`s also not supposed to do so.
There is an alternative to use LightCore as a service locator to get instances.
That can be instances, which are only valid in a methodscope -therefore local variables.
To achieve such as dynamic creation, the container instance is registered to the contract IContainer.
Imagine an article service, which have a "SaveAll" method.
On this method, an instance of ISaveService is needed, but only for the duration of the method call.
public class ArticleService : IArticleService
{
private readonly IContainer _container;
public ArticleService(IContainer container) {
this._container = container;
}
public SaveAll() {
var saveService = this._container.Resolve<ISaveService>();
// do something with the service.
}
}
Given the fact, that the container is registered to itself, the container detects automatically, whether a dependency is from contract IContainer or not.
It`s possible with ease, to use the LightCore container as service locator selective.
Easy explained: Allover where a service locator is needed, just put an IContainer dependency in your constructor.
Whether there other arguments too, or not, it just works everywhere.
Passing arguments at runtime
LightCore supports passing arguments at runtime, since version 1.4.
They can be named or not, and in every case typed.
If there is no type declared, LightCore chooses automatically string. That happends on the XML-Configuration.
You can see a few different constructors where called, on the following code.
Additional to this possibility, its also possible to pass in a dictionary with <string, object> direct.
The key (string) must have the name of the argument, and the value (object), the value of the argument.
var fooFromAnonymousType = container.Resolve<FooWithArguments>(new AnonymousArgument(new
{
arg1 = "Peter",
arg2 = true
}));
var fooFromPassedArgs = container.Resolve<FooWithArguments>("Peter", true);
var fooFromAList = container.Resolve<FooWithArguments>(new List<object> {"Peter", true});
Create registrations on demand
LightCore can create registrations on demand.
With this, support of open generic types is possible, and a lot more features.
All of the above possiblities can be used explicit with a Resolve()-Call, or implicit with a declared constructor argument, or a property.
Open Generic
Given a registered open generic type is registered, it is possible to use it with any typearguments.
If that happend, every time - if not exists - the container adds implicit a registration.
IRepository<Foo> repository = conainer.Resolve<IRepository<Foo>>;
IEnumerable / Array
If there is a request for a dependency as a array or ienumerable type. The container returns all instances, which are registered.
public FooBar(IEnumerable<IFooPlugin> fooPlugins)
{
/...
}
Factory
If a Func<T> dependency is requested, with one or more typearguments,
LightCore creates a factory on-the-fly for injection..
Therefore it`s possible to use factories instead of container injection.
It`s special, that the typearguments (T1, T2, TResult), all - except TResult - can used as constructor arguments.
That means, LightCore generates a factory, and you pass arguments you like.
The factory returns every time a new instance (transient behaviour).
See the following example.
public FooBar(Func<FooRepository> factory, Func<string, int, FooRepository> factoryWithArguments)
{
FooRepository repositoryOne = factory();
FooRepository repositoryTwo = factory();
FooRepository repositoryWithArguments = factoryWithArguments("Peter", 4);
}
Lazy (Since .NET 4.0)
Since .NET 4.0, a new type named Lazy<T> is available.
To create a new lazy instance, you have to pass a factory (Func<T>).
On the first reques to the value (.Value property), the factory will be called.
You get the same instance on subsequent requests to the property.
With this strategy, you can save performance, if it`s possible, not all services are needed every time,
and it`s the case, that the creation of an service takes very much time.
public FooBar(Lazy<FooService> lazyFooService)
{
FooService fooService = lazyFooService.Value; // factory executed.
FooService fooServiceTwo = lazyFooService.Value; // same value as above.
}
Resolve anything (automatic resolve any concrete type)
There exists not only a few cases, ony a concrete class is available,
and the concrete class have dependencies e.g. to abstractions.
If e.g. a FooService is requested, and the FooService has a dependency to a ILogger,
LightCore automatically registers the concrete type (FooService) to itself and resolves it.
That means: The best constructor will be choosed and the dependencies injected, as by a usual dependency.
If a concrete type used as dependency anywhere, the same will happend.
This kind of resolution holds the lowest priority, if LightCore asking for RegistrationSource`s.
FooService fooService = container.Resolve<FooService>(); // FooService is a concrete type.
public FooBar(FooService fooService)
{
ILogger = fooService.Logger; // logger was injected by LightCore.
}