Granit.Analyzers
Granit.Analyzers provides Roslyn analyzers that enforce Granit conventions at compile time, with immediate feedback in the IDE (red squiggles). They complement runtime checks and architecture tests with zero-cost static analysis.
Installation
Section titled “Installation”dotnet add package Granit.AnalyzersThe package ships both analyzers and code fix providers. No additional configuration is required — rules activate automatically based on the project’s dependencies.
Architecture
Section titled “Architecture”Rules enforcing modular monolith boundaries.
| Rule | Severity | CodeFix | Description |
|---|---|---|---|
| GRMOD001 | Error | Yes | Cross-module reference to internal type — use Contracts |
GRMOD001 — Cross-module reference detection
Section titled “GRMOD001 — Cross-module reference detection”Detects when code in one module references internal types from another module
instead of using the .Contracts namespace.
Applies to: projects using the *.Modules.{ModuleName} namespace convention.
Opt-in: the analyzer only activates when *.Modules.* namespaces are present
in the compilation. Projects without this convention pay zero runtime cost.
Allowed references:
- Types in
*.Modules.{Module}.Contractsand sub-namespaces - Types within the same module
- Types outside
*.Modules.*(framework, BCL, shared libraries)
Forbidden references:
- Types in
*.Modules.{OtherModule}.Domain - Types in
*.Modules.{OtherModule}.Handlers - Types in
*.Modules.{OtherModule}.Services - Any non-Contracts namespace of another module
CodeFix: if a type with the same name exists in the target module’s .Contracts
namespace, the code fix suggests replacing the using directive.
// ❌ GRMOD001: InventoryService from module Inventory cannot be// referenced from module Ordersusing MyApp.Modules.Inventory.Services;
namespace MyApp.Modules.Orders.Handlers;
public class OrderHandler(InventoryService inventory) { }// ✅ Use the Contracts namespaceusing MyApp.Modules.Inventory.Contracts;
namespace MyApp.Modules.Orders.Handlers;
public class OrderHandler(IInventoryReader inventory) { }Migrations
Section titled “Migrations”Rules enforcing zero-downtime migration patterns (expand/migrate/contract).
| Rule | Severity | CodeFix | Description |
|---|---|---|---|
| GRMIGA001 | Error | — | DropColumn requires a Contract-phase annotation |
| GRMIGA002 | Error | — | RenameColumn is not zero-downtime safe |
| GRMIGA003 | Warning | — | AddColumn NOT NULL without default risks table lock |
| GRMIGA004 | Warning | — | AlterColumn type change requires Contract-phase annotation |
Security
Section titled “Security”Rules enforcing testability, secret management, and GDPR compliance.
| Rule | Severity | CodeFix | Description |
|---|---|---|---|
| GRSEC001 | Warning | Yes | Avoid DateTime.Now/UtcNow — use IClock |
| GRSEC002 | Warning | Yes | Avoid Guid.NewGuid() — use IGuidGenerator |
| GRSEC003 | Error | — | Potential hardcoded secret detected |
| GRSEC004 | Warning | Yes | Avoid direct IResponseCookies — use IGranitCookieManager |
Entity Framework
Section titled “Entity Framework”Rules enforcing async-first EF Core patterns.
| Rule | Severity | CodeFix | Description |
|---|---|---|---|
| GREF001 | Warning | Yes | Use SaveChangesAsync() instead of SaveChanges() |
Rules enforcing Minimal API conventions and RFC 7807 compliance.
| Rule | Severity | CodeFix | Description |
|---|---|---|---|
| GRAPI001 | Warning | Yes | Use TypedResults instead of Results for OpenAPI |
| GRAPI002 | Warning | Yes | Use TypedResults.Problem() instead of BadRequest (RFC 7807) |
Suppressing rules
Section titled “Suppressing rules”To suppress a specific rule for a file or project:
// File-level suppression#pragma warning disable GRMOD001<!-- Project-level suppression in .csproj --><PropertyGroup> <NoWarn>$(NoWarn);GRMOD001</NoWarn></PropertyGroup>