Watch Out Abstract Dependency
The context is a C# .NET Core WebAPI system. The system employs the Onion Architecture. There is an API layer which is ASP.NET MVC controller. Then there is an Application Service layer inside the API layer. In the core of the onion, it is the domain. One can quickly google for Onion Architecture. If you do not know it, I suggest you take a look at it first.
One of a key points in the Onion Architecture is the inner layer must not know the outer layer. Which translates into the C# project that the Application Service Layer must not reference directly to the API project. The API consumes the Application Service NOT the other way around.
There is a requirement that application configuration (note that it is not system configuration like connection string, certificates …) should be maintained in a JSON file. Let’s call it appConfig.json. The file is deployed with the API. The implementation takes the advantage of .NET Core JSON configuration so the runtime can load the file.
Let simplify the requirement to focus on the architecture. The appConfig defines the default currency. The value is used to display in the UI and for other processing in the Application Service.
Come to the tricky part. Where do we should place the implementation: API or Application Service?
My answer is always in the API. What if the implementation is in the Application Service? Let’s see the implementation and analyze.
By using the IConfiguration interface, the Application Service has a dependency on Microsoft.Extensions.Configuration package which seems fine. Because it is abstraction.
Has the dependency between API and Application Service changed? Implementation-wise NO. Because there is no direct reference from Application Service to the API.
But there is in term of design. The Application Service implementation is using the infrastructure supplied by the API – the configuration is managed by the API layer.
Will it cause any problem? Well, it depends on what we care most about. If the architecture is the main concern, then yes, it is a problem. The architecture is broken unintentionally. Think about a scenarios where the Application Service is by another client, such as WPF application. Does it make sense to bring the Microsoft.Extensions.Configuration package to WPF application?
The Application Service defines the interface, which says “hey! I need to know the default currency, but I cannot figure it out by myself.” The outer layers, can be a WebAPI, can be WPF application, will supply the implementation, which says “Not a problem! I know where to get the default currency for you.”