Note
These docs are a work in progress. While conceptually correct, the diagrams/code samples on this page might not be 100% in line with the current implementation in Copper.
Extensibility
Context and problem
A common motivation to write your code, is the fact that existing frameworks cannot be configured or extended in a way that is suitable for your use case. The problem with writing your own code, is that you also have to maintain that. From versioning to bug fixes, you now have more code to maintain and work with on a daily basis. The code that gets written is also mostly plumbing code, code which does not add any business value, and is just there to "make it work for this framework".
Solution
Copper has a number of extensibility points which allow you to add custom behavior at certain points of the service lifecycle, or call chain. These points are discussed below.
- Component builder
- Dependency injection
- Interception
Component builder
Everything is a component in Copper, from the FabricRuntime emulator to the services and proxies.
Component Builder
Dependency injection container
Each component has their own child DI container. The following diagrams show the inheritance of dependencies. This is how you can control at what level you want to share or override a dependency.
Dependency injection
Just like most modern frameworks, Copper uses the Microsoft.Extensions DI framework to allow users to plug in their existing DI setup, or use popular libraries which have support for this. This makes it easy to use stuff you are familiar with, and it ensures that any documentation found online is applicable, which eases the adoption and smoothens the learning curve.
By allowing access to the DI container at service configuration, the possibilities are endless. Combined with the fact that we provide implementation details for our own code, overriding or customizing any class in the framework can be done easily and replaced using the DI container. This makes it so that we never have to modify the framework to adapt to any customer request as one can just add the behavior to the appropriate class. This can be done with out support if needed.
Interception
For the extensibility model on the call chain we use interception. This allows the user to inject behavior into the request pipeline which can be used for various use cases, and is also heavily used by the framework itself. Some examples of features that use this extensibility point are:
- Diagnostics
- Ambient operation context
- Validation
For interception we split our the incoming (Send - ISendInterceptor
) and outgoing (Receive - IReceiveInterceptor
) requests. Both can be added to the DI container at service configuration.