uid | level | summary |
---|---|---|
fabrics-many-projects |
300 |
The document provides instructions on how to add aspects to multiple projects in a repository using transitive project fabrics and common project fabrics, including their execution order. |
If you manage a repository or a solution composed of multiple projects, you may find it beneficial to add aspects from a central location. This article outlines several methods to achieve this.
These approaches are also applicable when configuring aspect libraries or adding architectural rules.
Transitive project fabrics are executed in any project that references the assembly containing the fabric, either as a project or package reference.
Transitive project fabrics are executed after any project fabric in the current project.
If multiple transitive project fabrics are active, they are executed in the following order:
- Depth in the dependency graph: dependencies with lower depth (i.e., "closer" to the main project) are processed first.
- Assembly name (in alphabetical order).
Transitive dependencies are intentionally executed after compilation dependencies, allowing the latter to configure transitive dependencies before they run.
Consider the following dependency graph:
flowchart BT
subgraph MySolution.Core
CoreTransitiveFabric
CoreClasses[Other types]
end
subgraph MySolution.Library1
Library1Classes[Other types]
end
MySolution.Library1 --> MySolution.Core
subgraph MySolution.Library2
Library2TransitiveFabric
Library2Classes[Other types]
end
MySolution.Library2 --> MySolution.Core
subgraph MySolution.App
AppClasses[Other types]
end
MySolution.App --> MySolution.Library1
MySolution.App --> MySolution.Library2
In MySolution
, the following transitive project fabrics will be active:
Project | Active transitive project fabrics |
---|---|
MySolution.Core |
None |
MySolution.Library1 |
CoreTransitiveFabric |
MySolution.Library2 |
CoreTransitiveFabric |
MySolution.App |
First CoreTransitiveFabric , then Library2TransitiveFabric |
Another approach is to rely on the directory structure instead of the dependency graph.
The concept is to write a project fabric, store it in the root directory of the repository, and automatically include this file in each project using Directory.Build.props.
In the parent directory that recursively contains all projects you want to be affected by the shared fabric, create a project fabric derived from xref:Metalama.Framework.Fabrics.ProjectFabric as you would do for a regular project fabric.
In the same directory, create a file named Directory.Build.props
with the following content:
<Project>
<!-- Imports Directory.Build.props of the upper directory. -->
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))"
Condition="Exists('$([MSBuild]::GetPathOfFileAbove(`Directory.Build.props`, `$(MSBuildThisFileDirectory)../`))')"/>
<!-- Include the shared fabric -->
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)SharedFabric.cs" />
</ItemGroup>
</Project>
See xref:sample-shared-fabric.
When you have multiple project fabrics in the same project, they are ordered by the following criteria:
- Distance of the source file from the root directory: fabrics closer to the root directory are processed first.
- Fabric namespace.
- Fabric type name.
Suppose we have the following project structure:
repo
+--- dir1
| +-- subdir11
| | +-- Project11.csproj
| | +-- Project11Fabric.cs
| +-- subdir12
| + Project12.csproj
+--- dir2
| +-- subdir21
| | +-- Project21.csproj
| +-- subdir22
| +-- Project22.csproj
| +-- Project21Fabric.cs
+-- SharedFabric.cs
+-- Directory.Build.props
Then the projects have the following fabrics:
Project | Active transitive project fabrics |
---|---|
Project11 |
SharedFabric , Project11Fabric |
Project12 |
SharedFabric |
Project21 |
SharedFabric |
Project12 |
SharedFabric , Project21Fabric |