The Decorator Pattern
For the purpose of the guide let's have following code structure
In above example, HttpService
is being decorated by LoggingService
as both implement common interface and
logging service wraps the HTTP service with added functionality.
Microsoft Dependency Injection
Unlike other dependency injection frameworks such as Unity or Castle Windsor, Microsoft Dependency Injection doesn't natively support circular dependency -
notice that LoggingService
implements IService
and at the same time accepts IService
in the constructor.
Unless you want to implement workarounds, the obvious solution is to use the rather mentioned Unity or Castle Windsor that supports decorator patterns out of the box. In case this is not an option for you, fortunately, an alternative exists - let's break the circular dependency with the flagging interface!
Flagging Interface For The Rescue
By using flagging interface we can break the circular dependency so that LoggingService
implementing IService
no longer accepts
IService
in the constructor. Let's take a look on the code snippet
Above we no longer have circular dependency. LoggingService
Implementing IService
injects now IHttpService
.
IHttpService
is adding no additional signatures, it serves purely as flag of the specific service.
Now we can use the native functionality of the Microsoft Dependency Injection freely and will achieve decorator functionality.
Beneficial Side Effect
Depending on your needs, the flagging interface might not be an option for you. Personally, I faced very few use cases when the usage of the flagging interface was not an option.
Additionally, the flagging interface brings a specific feature to the table - you define the order of decorations by design. In other words, you are explicitly stating in decorator class what type of interface you want to decorate by specifying concrete injected flagging interface. As an example let's imagine HTTP service, logging service, and caching service. You want to achieve execution in a specific order of logging service -> caching service -> HTTP service. By specifying the expected injected flagging interface, you no longer rely on the IoC configuration itself, instead, you have it strongly typed in the code design.
Closing Notes
I hope you found the flagging interface helping with decorator patterns a useful alternative to the workaround packages or techniques. In case you want to use the Microsoft Dependency Injection framework and want to inherit a common interface, there are workarounds available as e.g. Scrutor.