The standard SDK used by Blueshift Software to apply the hexagonal architecture pattern to MSBuild projects. This SDK is meant to be opinionated: it is primarily meant to reduce copy-and-paste boilerplate that can pollute and muddle MSBuild project files, while applying a standard and extensible set of hexagonal architecture rules.
Primarily, Blueshift.MSBuildSdk.Hexagonal enforces the Dependency Inversion Principle that is the underlying principle of hexagonal architecture. When applied to a core project that contains business logic, the Sdk enforces a minimal list of allowed packages that can be referenced by the project.
The SDK's allowed package "white-list" is customizable through MSBuild properties, which can be applied through environment variables, overriden in individual projects, included globally through Directory.Build.props/targets, via a Hexagonal.props in the repository root directory, or via specific before- and after.props and -.targets files.
Under hexagonal architecture, core business logic may not take any external dependencies. Instead, the business logic layer should declare its own dependencies - called ports - which must be fulfilled by a set of adapters. These adapters are consumed by the application front-end and injected into the core business logic at runtime. Doing so decouples the business logic from providers, making it more extensible, testable, and maintainable.
For example, a core business logic service should not take an SqlClient as a direct dependency. Doing so would couple the business logic to SQL, or even a particular flavor of SQL. This would in turn make it far more difficult to change to a different flavor of Sql, or even switch entirely to a NoSql database if the necessity arose. Instead, the core business logic should declare an interface for some kind of object repository - eg: IBookRepository - which can then be implemented in an adapter. The adapter would then implement this interface with a class named something such as SqlBookRepository, which can take a SqlClient as a dependency. At runtime, SqlBookRepository can be injected into the core business logic wherever an IBookRepository is required.
However, doing this for every single dependency in every project would necessarily create significant duplication across projects. Consider logging, for example. It's a generally accepted rule that all applications should log. However, forcing every hexagonal application to re-implement its own specific logging abstraction just to decouple each project from the ubiquitous task of logging is overly dogmatic. If a company has a core set of logging utilities, it is perfectly acceptable to reuse that across hexagonal projects.
Blueshift.MSBuildSdk.Hexagonal compromises by allowing a specific (extensible) set of packages to be referenced by a project. Currently, only the following packages are supported by default:
- Microsoft.Extensions.Configuration.Abstractions
- Microsoft.Extensions.DependencyInjection.Abstractions
- Microsoft.Extensions.Logging.Abstractions
- Microsoft.Extensions.Options
Note that everything aside from Options (for which there is no available abstraction layer) uses the abstraction. This allows only the interfaces to be used, which enforces the requirement for the entrypoint of the application to set up the necessary concrete implementations.
This list is extensible and overridable.
If a file called 'Hexagonal.props' is present in the root of the repository, it will automatically be imported. To extend the list of allowed packages, include an ItemGroup with one or more AllowedHexagonalPackage elements:
<Project>
<ItemGroup>
<AllowedHexagonalPackage Include="My.Allowed.Package" />
</ItemGroup>
</Project>This file is imported after the default list of allowed packages is created. This allows 'Hexagonal.props' to remove items from - or completely override - the default list. To do so, use the Remove attribute:
<Project>
<ItemGroup>
<AllowedHexagonalPackage Remove="Microsoft.Extensions.Options" /> <!-- Remove one item -->
<AllowedHexagonalPackage Remove="*" /> <!-- Clear the whole list -->
<AllowedHexagonalPackage Include="My.Allowed.Package" />
</ItemGroup>
</Project>If the project contains any package references that are not allowed via AllowedHexagonalPackage items in this manner, the Sdk will generate an error.
The behavior of the SDK can be fine-tuned by setting these specific propeties prior to loading the SDK:
| Property | Description |
|---|---|
| CustomBeforeBlueshiftMSBuildHexagonalSdkProps | The name of a custom props file to be loaded at the beginning of Sdk.props. |
| CustomAfterBlueshiftMSBuildHexagonalSdkProps | The name of a custom props file to be loaded at the end of Sdk.props. |
| CustomBeforeBlueshiftMSBuildHexagonalSdkTargets | The name of a custom targets file to be loaded at the beginning of Sdk.target. |
| CustomAfterBlueshiftMSBuildHexagonalSdkTargets | The name of a custom targets file to be loaded at the end of Sdk.target. |