Dependency injection#
AE.Extensions.DependencyInjection
packages are an extension library for Microsoft.Extensions.DependencyInjection
which provides you with a declarative way to pick out lifetime of services and register them in just a few lines.
Motivation#
When you want to register a service (create dependency) in IServiceCollection
you have to describe at least 3 things:
- Service interface
- Service implementation
- Lifetime scope
Usually it should look like this (see below)
// Method ex. in Startup.cs // doc: http://docs.asp.net/en/latest/fundamentals/dependency-injection.html public void ConfigureServices(IServiceCollection services) { var serviceDescriptor = new ServiceDescriptor(typeof(IBankManager), typeof(BankManager), ServiceLifetime.Transient); services.Add(serviceDescriptor); // or services.AddTransient<IBankManager, BankManager>(); // Add MVC services to the services container. services.AddMvc(); }
/// And service definition somewhere, deeper in the code public interface IBankManager { int OpenAccount(string clientName); } public class BankManager : IBankManager { public int OpenAccount(string clientName) { // Account creating process... return Random.Next(1000000, 9999999); } }
Every service must be described in ConfigureServices
method manualy which means that something can be easily missed.
Many people who create libraries like MVC they add static extension methods to simplify registration.
It means all descriptions of their services are hidden.
They make our life easier but what about our own custom services ? What if you have dozens of them ?
Overview#
I'm inspired by how Orchard team resolves that issue.
They created interfaces which correspond to lifetime scopes. So every service interface inherits appropriate "scope interface" and describes dependencies to register in global container.
In my case it looks like below - interfaces correspond exactly to ServiceLifetime
enum.
// You can use it to get all dependencies public interface IDependency { } public interface ISingletonDependency : IDependency { } public interface IScopedDependency : IDependency { } public interface ITransientDependency : IDependency { } // Omit registration for special cases public interface INotRegisterDependency { }
How does it work?#
In order to use this approach you have to do two things:
- Select dependency interface and inherit
// It will be registered as a // new ServiceDescriptor(typeof(IBankManager), typeof(BankManager), ServiceLifetime.Transient); public interface IBankManager : ITransientDependency { int OpenAccount(string clientName); } public class BankManager : IBankManager { public int OpenAccount(string clientName) { // Account creating process... return Random.Next(1000000, 9999999); } }
- Use extensions methods for
IServiceCollection
orServiceDescriptorsBuilder
to retrieve all dependencies from assemblies (see below)
public void ConfigureServices(IServiceCollection services) { var assemblies = ... Get all assemblies ex. by ILibraryLoader or Assembly.GetExecutingAssembly(...) etc. services.AddFromAssemblies(assemblies); // Add MVC services to the services container. services.AddMvc(); }
There are many custom ways to use service description builder. Most cases described in customizations section. Also you can find list of additional features here