A simple and lightweight way of applying the Decorator Pattern using Asp Net's dependency injection services. This lib is built on top of Microsoft.Extensions.DependencyInjection.Abstractions and allows services to be added to the service provider using a decorator pattern.
To install this lib, simply install the package from NuGet using the command below.
Install-Package DependencyInjection.Decorators
To register services in a decorator pattern you'll use one of the several extension methods for IServiceCollection
.
Each service lifetime supported in ServiceLifetime
enum has its own method:
- For Scoped:
AddDecoratedScoped
; - For Transient:
AddDecoratedTransient
; - For Singleton:
AddDecoratedSingleton
;
Alternatively you can use AddDecorated
and pass in the chosen service lifetime.
You'll find both generic and concrete extension methods.
Generic methods will support up to one component and five decorators. For more decorators use the concrete methods.
// generic methods
services.AddDecoratedScoped<IServiceToDecorate, Decorator3, Decorator2, Decorator1, Component>();
services.AddDecoratedTransient<IServiceToDecorate, Decorator3, Decorator2, Decorator1, Component>();
services.AddDecoratedSingleton<IServiceToDecorate, Decorator3, Decorator2, Decorator1, Component>();
//concrete methods
services.AddDecoratedScoped(serviceToDecorateType, decorator3Type, decorator2Type, decorator1Type, componentType);
services.AddDecoratedTransient(serviceToDecorateType, decorator3Type, decorator2Type, decorator1Type, componentType);
services.AddDecoratedSingleton(serviceToDecorateType, decorator3Type, decorator2Type, decorator1Type, componentType);
//one method to run them all
services.AddDecorated(serviceLifetime, serviceToDecorateType, decorator3Type, decorator2Type, decorator1Type, componentType);
The lib uses the factory overload of IServiceCollection.Add
method to register the service Type and do its job.
All types passed to AddDecorated
methods, except the service type, are registered using the same service lifetime, so there is no need to register them prior to calling AddDecorated
.
The factory for the service type, at runtime, instances all services registered, from right to left, using a combination of IServiceProvider
and ActivatorUtilities
, passing the last instanced service as constructor parameter for the next.
This means that the call order, based on the example above, is: Decorator3 -> Decorator2 -> Decorator1 -> Component. (for more details on this matter, check the test project)
- All types are registered by the
AddDecorated
methods; - All types are registered with the same lifetime;
- Instances are created from right to left, each one being inject into the next;
- At runtime, calls to the service execute from left to right.
If you find bugs and don't have time to submit a PR, please report it using Github isses. On the other hand, if you can submit a PR I'll gladly take a look at it.