ArchGuard.Net
1.0.0
dotnet add package ArchGuard.Net --version 1.0.0
NuGet\Install-Package ArchGuard.Net -Version 1.0.0
<PackageReference Include="ArchGuard.Net" Version="1.0.0" />
<PackageVersion Include="ArchGuard.Net" Version="1.0.0" />
<PackageReference Include="ArchGuard.Net" />
paket add ArchGuard.Net --version 1.0.0
#r "nuget: ArchGuard.Net, 1.0.0"
#:package ArchGuard.Net@1.0.0
#addin nuget:?package=ArchGuard.Net&version=1.0.0
#tool nuget:?package=ArchGuard.Net&version=1.0.0
![]()
ArchGuard.NET
Target framework: net10.0 · Language: C# · Test runner: xUnit
ArchGuard.NET helps you stop architecture drift in .NET solutions. It is designed for teams who want practical guard rails without adopting a heavy architecture framework.
What is ArchGuard.NET?
ArchGuard.NET is a lightweight architecture testing helper for modern .NET solutions. You write simple xUnit tests that enforce project, namespace, module and dependency boundaries. When a rule is broken, the build fails with clear, CI-friendly output.
The standout feature is baseline support. Existing violations can be recorded in a JSON baseline file so legacy issues are accepted temporarily, while new violations still fail the build.
Why architecture tests
Codebases rarely break all at once. They drift: a domain type references infrastructure, one module reaches into another module's database layer, or an API controller starts using EF Core directly. These changes compile and ship easily, but they erode boundaries that keep your system maintainable.
Architecture tests turn those boundaries into executable rules. They are cheap to run in CI and give fast feedback before a pull request merges.
Installation
dotnet add package ArchGuard.Net
See PUBLISHING.md for how releases are published via NuGet trusted publishing.
Add a test project if you do not already have one:
dotnet new xunit -n MyCompany.Architecture.Tests
dotnet add MyCompany.Architecture.Tests package ArchGuard.Net
Quick start
using ArchGuard;
public sealed class ArchitectureTests
{
[Fact]
public void Domain_must_not_reference_infrastructure()
{
ArchitectureRules
.ForAssemblies(typeof(MyCompany.Domain.Order).Assembly)
.NoNamespace("MyCompany.Domain")
.ShouldDependOn("MyCompany.Infrastructure")
.Assert();
}
}
Scan all matching assemblies from the test working directory (current directory only by default):
ArchitectureRules
.ForAssembliesFromCurrentDirectory("MyCompany.*.dll")
.NoNamespace("MyCompany.Domain")
.ShouldDependOn("MyCompany.Infrastructure")
.Assert();
Use SearchOption.AllDirectories when assemblies are spread across nested build output folders.
Modular monolith example
ArchitectureRules
.ForAssembliesFromCurrentDirectory("MyCompany.*.dll")
.UseModularMonolith(options =>
{
options.ModuleNamespaceRoot = "MyCompany.App.Modules";
options.AllowedCrossModuleNamespaces =
[
".Contracts",
".Client"
];
})
.Assert();
Modules are expected under MyCompany.App.Modules.{ModuleName}. Cross-module dependencies are allowed only into .Contracts or .Client namespaces within another module. The rule also blocks infrastructure leaks across module boundaries (SF004).
Vertical slice example
ArchitectureRules
.ForAssembliesFromCurrentDirectory("MyCompany.*.dll")
.UseVerticalSlices(options =>
{
options.FeatureNamespaceRoot = "MyCompany.App.Features";
options.AllowSharedKernel = true;
options.SharedKernelNamespace = "MyCompany.App.Shared";
})
.Assert();
Features under MyCompany.App.Features.{FeatureName} must not depend directly on other features. Shared kernel dependencies are allowed when configured.
Layering example
ArchitectureRules
.ForAssembliesFromCurrentDirectory("MyCompany.*.dll")
.EnforceLayers(options =>
{
options.Layer("Api", "MyCompany.App.Api");
options.Layer("Application", "MyCompany.App.Application");
options.Layer("Domain", "MyCompany.App.Domain");
options.Layer("Infrastructure", "MyCompany.App.Infrastructure");
options.Layer("Domain").MayNotDependOn("Application", "Infrastructure", "Api");
options.Layer("Application").MayNotDependOn("Api");
options.Layer("Infrastructure").MayNotDependOn("Api");
})
.Assert();
API boundary example
ArchitectureRules
.ForAssembliesFromCurrentDirectory("MyCompany.*.dll")
.ApiShouldNotUseEfCoreDirectly("MyCompany.App.Api")
.Assert();
This fails when API types depend directly on Microsoft.EntityFrameworkCore, DbContext, or DbSet<>.
Baseline example
For existing codebases, record current violations once and then fail only on new ones:
[Fact]
public void Architecture_should_not_have_new_violations()
{
ArchitectureRules
.ForAssembliesFromCurrentDirectory("MyCompany.*.dll")
.UseModularMonolith(options =>
{
options.ModuleNamespaceRoot = "MyCompany.App.Modules";
options.AllowedCrossModuleNamespaces = [".Contracts", ".Client"];
})
.WithBaseline("architecture-baseline.json")
.FailOnlyOnNewViolations()
.Assert();
}
Commit architecture-baseline.json to source control. Violations already listed in the baseline are suppressed.
If the baseline file does not exist yet, the test fails with guidance on how to create one.
Updating a baseline
Run this explicitly when you want to refresh accepted violations. Do not run it on every CI build.
[Fact]
public void Update_architecture_baseline()
{
ArchitectureRules
.ForAssembliesFromCurrentDirectory("MyCompany.*.dll")
.UseModularMonolith(options =>
{
options.ModuleNamespaceRoot = "MyCompany.App.Modules";
options.AllowedCrossModuleNamespaces = [".Contracts", ".Client"];
})
.WithBaseline("architecture-baseline.json")
.UpdateBaseline()
.Assert();
}
This writes all current violations to the baseline file and does not fail the test.
CI usage
Add an architecture test project to your pipeline:
- name: Run architecture tests
run: dotnet test MyCompany.Architecture.Tests/MyCompany.Architecture.Tests.csproj --configuration Release
Failure output is grouped by rule ID and includes baseline summary information:
ArchGuard.NET found 3 new architecture violation(s).
Baseline:
File: architecture-baseline.json
Suppressed existing violations: 14
Stale baseline entries: 2
SF003 Modular monolith cross-module dependency
MyApp.Modules.Claims.Features.GetClaimHandler
depends on MyApp.Modules.Submissions.Infrastructure.SubmissionDbContext
Stale baseline entries are reported so your team can clean up the baseline when old violations are fixed.
Mermaid dependency graph
Generate a simple graph from violation dependencies:
var result = ArchitectureRules
.ForAssembliesFromCurrentDirectory("MyApp.*.dll")
.UseModularMonolith(options =>
{
options.ModuleNamespaceRoot = "MyApp.Modules";
})
.Evaluate();
ArchGuard.Reporting.MermaidDependencyGraphWriter.Write(result, "architecture-graph.md");
Rule reference
| Rule ID | Name |
|---|---|
| SF001 | No namespace dependency |
| SF002 | Layer dependency rule |
| SF003 | Modular monolith cross-module dependency |
| SF004 | Module infrastructure leak |
| SF005 | Vertical slice cross-feature dependency |
| SF006 | API direct EF Core dependency |
Current limitations
- Dependency scanning uses Mono.Cecil and inspects compiled assemblies. Source-only projects must be built before scanning.
- Layer and namespace rules compare by namespace prefix, not by project or folder structure.
- The dependency scanner ignores
System.*andMicrosoft.*references by default, except when a rule opts in (for example the EF Core API rule). - Method body analysis is best-effort and may not catch every indirect dependency.
- The Mermaid graph writer is a simple overview based on violations, not a full dependency map.
Building from source
git clone https://github.com/kearns2000/ArchGuard.NET.git
cd ArchGuard.NET
dotnet build -c Release
dotnet test -c Release
Contributing
Contributions are welcome. See CONTRIBUTING.md for setup, project layout, and how to add rules or tests.
Please read our Code of Conduct before participating.
Licence
MIT. See LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Mono.Cecil (>= 0.11.6)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 95 | 7/6/2026 |