ArchGuard.Net 1.0.0

dotnet add package ArchGuard.Net --version 1.0.0
                    
NuGet\Install-Package ArchGuard.Net -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ArchGuard.Net" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ArchGuard.Net" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ArchGuard.Net" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ArchGuard.Net --version 1.0.0
                    
#r "nuget: ArchGuard.Net, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ArchGuard.Net@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ArchGuard.Net&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ArchGuard.Net&version=1.0.0
                    
Install as a Cake Tool

ArchGuard.NET

ArchGuard.NET

NuGet .NET Build Licence: MIT Tests

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.* and Microsoft.* 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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