FabricOrg.Platform.Testing
1.4.0
dotnet add package FabricOrg.Platform.Testing --version 1.4.0
NuGet\Install-Package FabricOrg.Platform.Testing -Version 1.4.0
<PackageReference Include="FabricOrg.Platform.Testing" Version="1.4.0" />
<PackageVersion Include="FabricOrg.Platform.Testing" Version="1.4.0" />
<PackageReference Include="FabricOrg.Platform.Testing" />
paket add FabricOrg.Platform.Testing --version 1.4.0
#r "nuget: FabricOrg.Platform.Testing, 1.4.0"
#:package FabricOrg.Platform.Testing@1.4.0
#addin nuget:?package=FabricOrg.Platform.Testing&version=1.4.0
#tool nuget:?package=FabricOrg.Platform.Testing&version=1.4.0
FabricOrg.Platform
TypeScript is the reference governance contract. FabricOrg.Platform.Host persists
GovernanceRuntimeEvidence on each new invocation so operators can identify the exact governance,
Host, provider bridge, and policy generations that authorized a historical mutation. C# tests run
the language-neutral fixture vendored under contracts/fabric-family, while the shared CI action
requires it to remain byte-identical to Platform's canonical copy.
A governance kernel for .NET that enforces a single, auditable mutation pipeline for every domain state change. Every write flows through one canonical door (
IActionRuntime.InvokeAsync), producing an immutable audit trail ofActionInvocation,PolicyEvaluation, andAssetEventrecords.
This is the .NET-native port of the TypeScript @fabricorg/platform governance framework. It targets .NET Standard 2.1 for broad compatibility and integrates seamlessly with Microsoft Orleans, ASP.NET Core, and vanilla .NET applications.
Packages
| Package | Description | Target |
|---|---|---|
FabricOrg.Platform |
Core runtime — action pipeline, policy engine, state machines, event sourcing | netstandard2.1 |
FabricOrg.Platform.Abstractions |
Interfaces and types — referenced by vertical modules | netstandard2.1 |
FabricOrg.Platform.DependencyInjection |
IServiceCollection extensions |
netstandard2.1 |
FabricOrg.Platform.FluentValidation |
FluentValidation → ISchemaValidator bridge |
netstandard2.1 |
FabricOrg.Platform.Host |
Durable host — PostgreSQL, recovery, HITL, obligations, attestations, reconciliation | net8.0 |
FabricOrg.Platform.Orleans |
Orleans grain base classes and interceptors | netstandard2.1 |
FabricOrg.Platform.Polly |
Polly-based retry and circuit-breaker | netstandard2.1 |
FabricOrg.Platform.Policies.OpenPolicyAgent |
OPA (Open Policy Agent) integration | netstandard2.1 |
FabricOrg.Platform.Sdk |
HTTP SDK for external consumers | netstandard2.1 |
FabricOrg.Platform.Analyzers |
Roslyn analyzers — development dependency only | netstandard2.0 |
Quick Start
1. Install Packages
dotnet add package FabricOrg.Platform
dotnet add package FabricOrg.Platform.DependencyInjection
dotnet add package FabricOrg.Platform.FluentValidation
dotnet add package FabricOrg.Platform.Host
dotnet add package FabricOrg.Platform.Analyzers # Dev dependency
2. Define a Module
public class LendingModule : IFabricModule<AppDbContext>
{
public string Namespace => "lending";
public string DisplayName => "Lending";
public IReadOnlyList<ActionDefinition<AppDbContext>> Actions => new[]
{
new ActionDefinition<AppDbContext>
{
ActionId = ActionId.Parse("lending.accept_offer"),
Namespace = "lending",
Version = 1,
Schema = new FluentValidationSchemaValidator(new AcceptOfferValidator()),
Handler = AcceptOfferHandler.ExecuteAsync,
RequiredRoles = new[] { "loan_consultant", "underwriter" },
RequiredPermissions = new[] { "lending.offer.accept" },
EmitsEvents = new[] { "OfferAccepted", "StateTransitioned" },
Idempotent = true,
MutatesDomain = true,
StateMachine = new ActionStateMachineBinding(
EntityType: "Offer",
TargetStateResolver: p => "accepted",
EntityIdResolver: p => ((AcceptOfferCommand)p).OfferId)
}
};
public IReadOnlyList<StateMachineDefinition> StateMachines => new[]
{
new StateMachineDefinition(
EntityType: "Offer",
States: new Dictionary<string, StateDefinition>
{
["generated"] = new("generated", "Generated", StateClass.Initial),
["presented"] = new("presented", "Presented", StateClass.Active),
["accepted"] = new("accepted", "Accepted", StateClass.Terminal),
["declined"] = new("declined", "Declined", StateClass.Terminal),
["expired"] = new("expired", "Expired", StateClass.Terminal)
},
Transitions: new[]
{
new StateTransition("generated", "presented", ActionId.Parse("lending.present_offer")),
new StateTransition("presented", "accepted", ActionId.Parse("lending.accept_offer")),
new StateTransition("presented", "declined", ActionId.Parse("lending.decline_offer")),
new StateTransition("presented", "expired", ActionId.Parse("lending.expire_offer"))
})
};
// ... policies, events, adapters
}
3. Register in Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddFabricGovernance<AppDbContext>(options =>
{
options.ValidateModulesOnStartup = true;
options.EnforceBoundaryChecks = true;
});
builder.Services.AddFabricModule(new LendingModule());
// Optional: override with Orleans, Temporal, etc.
// builder.Services.WithSagaOrchestrator<TemporalSagaOrchestrator>();
// builder.Services.WithAsyncJobDispatcher<TemporalJobDispatcher>();
var app = builder.Build();
4. Invoke an Action
public class OffersController : ControllerBase
{
private readonly IActionRuntime _runtime;
private readonly AppDbContext _db;
public OffersController(IActionRuntime runtime, AppDbContext db)
{
_runtime = runtime;
_db = db;
}
[HttpPost("{offerId}/accept")]
public async Task<IActionResult> Accept(string offerId)
{
var result = await _runtime.InvokeAsync(new InvokeActionRequest(
ActionId.Parse("lending.accept_offer"),
new Dictionary<string, object?> { ["offerId"] = offerId },
User.Identity.Name!,
ActorType.NaturalPerson,
tenantId: "tenant_123",
spaceId: "space_456"
), _db);
return result.Status == ActionStatus.Completed
? Ok(result)
: BadRequest(result);
}
}
5. Orleans Integration
public class OfferGrain : GovernedGrain<IOfferRepository>, IOfferGrain
{
public OfferGrain(IActionRuntime runtime, IOfferRepository db) : base(runtime, db) { }
public async Task<Result> AcceptAsync(AcceptOfferCommand command, ActorContext actor)
{
var result = await InvokeActionAsync(new InvokeActionRequest(
ActionId.Parse("lending.accept_offer"),
command.ToDictionary(),
actor.ActorId,
actor.ActorType,
actor.TenantId,
actor.SpaceId
));
return result.Status == ActionStatus.Completed
? Result.Success()
: Result.Failure(result.Error);
}
}
Architecture
┌─────────────────────────────────────────────────────────────┐
│ SaaS UI │ Borrower Portal │ Temporal Cron │ Agent │
└────┬────────────┬─────────────────┬───────────────┬─────────┘
│ │ │ │
│ natural_person external_system system agent
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ API Layer (Host Application) │
│ • IActionRuntime.InvokeAsync │
│ • IActionRuntime.PreviewAsync │
└────────────────────────┬────────────────────────────────────┘
│
▼
┌───────────────────────────────┐
│ FabricOrg.Platform Runtime │
│ - Module entitlement check │
│ - Permission check (HITL) │
│ - Create ActionInvocation │
│ - Policy evaluation │
│ - State machine validation │
│ - Execute handler (TDb txn) │
│ - Append AssetEvent │
│ - Execute adapters │
└───────────────────────────────┘
│
▼
┌───────────────────────────────┐
│ Vertical Handlers (lending) │
│ e.g. acceptOfferHandler │
└───────────────────────────────┘
Governance Capabilities
- Single Mutation Path — All domain writes flow through
IActionRuntime.InvokeAsync. Boundary analyzers enforce this at compile time. - Policy Engine — Code policies (C# evaluators), data policies (declarative condition trees), and hybrid policies with full
PolicyDispatchEvidenceaudit. - State Machines — Declarative transition graphs with guards. Invalid transitions are blocked before handlers run.
- Audit Trail — Immutable
ActionInvocation,PolicyEvaluation, andAssetEventrecords with correlation IDs. - Adapter Orchestration — Retry, circuit breaker, and dead-letter queue for external service calls.
- Agent HITL — Human-in-the-loop policy routing for AI agents (
auto-execute,needs-approval,escalate,rejected). - Durable Host —
FabricOrg.Platform.Hostprovides the canonical invocation ledger, PostgreSQL persistence, worker recovery, idempotency, redaction, exact HITL approval resume, external mutation footprints, delegated principals, policy obligations, execution attestations, and reconciliation evidence used by vertical applications. - Privacy & Redaction — Field-level redaction rules, data classification, retention policies, and anonymization.
- Evidence Packets — Curated compliance bundles linking actions, events, policies, and external documents.
- Projections — Deterministic event replay with snapshot support.
- Telemetry —
System.Diagnostics.ActivitySourcespans for distributed tracing.
Durable agent approval
The .NET runtime uses the same HITL route and risk vocabulary as @fabricorg/platform.
Per-action rules stay in an IAgentActionPolicyRegistry; the runtime owns stage placement and
durable lifecycle semantics:
- Agent decisions run after validation and authorization, before ordinary policies and handlers.
needs-approvalandescalatepark the invocation asWaitingForApprovalwithout side effects.rejectedterminates asFailed;auto-executecontinues through the governed pipeline.IApprovalActionInvocationRecorder<TDb>durably stores route/risk evidence and atomically applies an approval decision. ExistingIActionInvocationRecorder<TDb>implementations remain compatible.IApprovalActionRuntime.ResumeApprovedInvocationAsync(...)resumes after the HITL checkpoint, so workflow adapters do not bypass policy, state-machine, handler, event, or adapter stages.
var result = await approvalRuntime.ResumeApprovedInvocationAsync(
actionInvocationId,
tenantId,
spaceId,
new ActionApprovalDecision(
approverId: userId,
approverType: ActorType.NaturalPerson,
approved: true,
reason: "Reviewed"),
db,
cancellationToken);
Approval replay is terminal-safe, and tenant/space mismatches cannot resume an invocation. Hosts that
support approval must persist the original validated execution input and implement the atomic
waiting-to-pending/failed transition defined by IApprovalActionInvocationRecorder<TDb>.
Repository Structure
FabricOrg.Platform/
├── src/
│ ├── FabricOrg.Platform/ # Core runtime
│ ├── FabricOrg.Platform.Abstractions/ # Contracts
│ ├── FabricOrg.Platform.DependencyInjection/ # DI extensions
│ ├── FabricOrg.Platform.FluentValidation/ # Validation bridge
│ ├── FabricOrg.Platform.Orleans/ # Orleans integration
│ ├── FabricOrg.Platform.Polly/ # Resilience
│ ├── FabricOrg.Platform.Policies.OpenPolicyAgent/ # OPA
│ └── FabricOrg.Platform.Sdk/ # HTTP SDK
├── analyzers/
│ └── FabricOrg.Platform.Analyzers/ # Roslyn analyzers
├── tests/
│ ├── FabricOrg.Platform.Tests/
│ ├── FabricOrg.Platform.IntegrationTests/
│ ├── FabricOrg.Platform.Orleans.Tests/
│ └── FabricOrg.Platform.Sdk.Tests/
├── samples/
│ ├── MinimalVertical/ # Console app demo
│ ├── OrleansVertical/ # Orleans silo demo
│ └── AgentSdkSample/ # External agent demo
├── docs/
│ ├── architecture/
│ ├── api/
│ └── migration-from-typescript.md
└── PLAN.md # Implementation plan
Building
dotnet build
Testing
dotnet test
Samples
See the samples/ directory for working examples:
- MinimalVertical — Console application with EF Core + in-memory database
- OrleansVertical — Orleans silo with governed grains
- AgentSdkSample — External agent using the HTTP SDK
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. 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. |
-
net8.0
- FabricOrg.Platform (>= 1.4.0)
- FabricOrg.Platform.Abstractions (>= 1.4.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.