Skip to main content

Excalibur

Excalibur is a modern, high-performance .NET framework for building scalable applications. Start with Excalibur.Dispatch for type-safe message dispatching, then add domain modeling, event sourcing, and sagas as your architecture requires. Whether you're building a simple CRUD API or a complex distributed system, Excalibur handles the infrastructure so you can focus on business logic.

At a Glance

SignalValue
Automated Tests55,000+ (unit, integration, conformance, performance)
Packages197 NuGet packages across 6 families
CI Pipeline10 sharded test stages, governance gates, conformance suites
API StabilityPublicAPI analyzer tracking on every package
Target Framework.NET 10.0

Tamper-Evident Audit Trails

Compliance-grade audit stores (SQL Server, PostgreSQL) hash-chain every audit event — each record is cryptographically linked to the one before it — so the trail is verifiable, not merely stored. A single altered, inserted, or deleted record breaks the chain and is detected, with the exact offending event pinpointed. One call verifies an entire time range:

using Excalibur.Compliance;

// Verify the audit trail for the last 30 days has not been tampered with.
public static async Task<bool> IsAuditTrailIntactAsync(IAuditQuery audit, CancellationToken ct)
{
AuditIntegrityResult result = await audit.VerifyChainIntegrityAsync(
startDate: DateTimeOffset.UtcNow.AddDays(-30),
endDate: DateTimeOffset.UtcNow,
cancellationToken: ct);

// result.EventsVerified were checked; if the chain is broken,
// result.FirstViolationEventId and result.ViolationDescription pinpoint it.
return result.IsValid;
}

Audit events also stream to SIEM and observability sinks — AWS, Datadog, Elasticsearch, Google Cloud, OpenSearch, Microsoft Sentinel, and Splunk — for search and alerting (these are write-only projections, not compliance stores). See Audit Logging for the compliance boundary, setup, and the full backend list.

What Excalibur.Dispatch Does

Excalibur.Dispatch handles how messages flow through your system:

  • Message Dispatching — Send actions to handlers with full type safety
  • Pipeline Behaviors — Add cross-cutting concerns like validation, logging, and transactions
  • Multi-Transport Support — Route messages to Kafka, RabbitMQ, Azure Service Bus, and more
  • Result Handling — Clean success/failure patterns without exceptions
  • Context Propagation — Automatic correlation ID and metadata tracking

Package Families

Excalibur is one framework with focused package families. Install only what you need:

Package FamilyPurpose
Excalibur.Dispatch.*Messaging, pipeline, handlers, transports
Excalibur.DomainDomain modeling (aggregates, entities, value objects)
Excalibur.EventSourcing.*Event stores, snapshots, persistence
Excalibur.Saga.*Sagas and process managers
Excalibur.Hosting.*ASP.NET Core, serverless hosting templates

See the Package Guide for selection help, migration paths, and code examples.

Excalibur.Dispatch vs MediatR

If you're familiar with MediatR, you'll feel right at home. Here's how concepts map:

MediatRDispatchNotes
IRequestIDispatchActionActions without return value
IRequest<TResponse>IDispatchAction<TResult>Actions with return value
IRequestHandler<T>IActionHandler<T>Handler without return
IRequestHandler<T, R>IActionHandler<T, R>Handler with return
INotificationIDispatchEventEvents/notifications
INotificationHandler<T>IEventHandler<T>Event handlers
IMediatorIDispatcherMessage dispatcher

Key improvements over MediatR (all included in Excalibur.Dispatch):

  • Results carry to the HTTP edge, no boilerplate — a handler returns a railway-style IMessageResult, and .ToHttpResult() maps it to the correct response automatically: 403 when authorization failed, 400 when validation failed, ProblemDetails (with its status) for structured errors, 500 for unstructured failures, and 200 / 202 / 201 / 204 on success. With MediatR you hand-write that mapping in every endpoint.
  • Pluggable AuthN/AuthZ/Audit, fail-closed by default — authorization speaks native ASP.NET Core [Authorize] / AuthorizationHandler, and denies when the decision is missing rather than falling open.
  • Automatic context propagation for distributed tracing
  • Multi-transport routing support
  • Performance optimizations for high-throughput scenarios
// A handler returns a result; the endpoint maps it to the right HTTP status with one call.
app.MapPost("/orders", async (CreateOrderRequest req, IDispatcher dispatcher, CancellationToken ct) =>
{
var result = await dispatcher.DispatchAsync(new CreateOrderAction(req.CustomerId, req.Items), ct);
return result.ToHttpResult(); // 202 on success; 403/400/ProblemDetails/500 on failure — no manual mapping
});

Quick Start

1. Install the Package

dotnet add package Excalibur.Dispatch

2. Define an Action

using Excalibur.Dispatch;

// Action without return value
public record CreateOrderAction(string CustomerId, List<string> Items) : IDispatchAction;

// Action with return value
public record GetOrderAction(Guid OrderId) : IDispatchAction<Order>;

3. Create a Handler

using Excalibur.Dispatch.Delivery;

public class CreateOrderHandler : IActionHandler<CreateOrderAction>
{
private readonly IOrderRepository _repository;

public CreateOrderHandler(IOrderRepository repository)
{
_repository = repository;
}

public async Task HandleAsync(
CreateOrderAction action,
CancellationToken cancellationToken)
{
var order = new Order
{
Id = Guid.NewGuid(),
CustomerId = action.CustomerId,
Items = action.Items
};

await _repository.SaveAsync(order, cancellationToken);
}
}

4. Register and Dispatch

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDispatch(dispatch =>
{
dispatch.AddHandlersFromAssembly(typeof(Program).Assembly);
});

var app = builder.Build();

// In your controller or service
public class OrderController : ControllerBase
{
private readonly IDispatcher _dispatcher;

public OrderController(IDispatcher dispatcher)
{
_dispatcher = dispatcher;
}

[HttpPost]
public async Task<IActionResult> CreateOrder(
CreateOrderRequest request,
CancellationToken cancellationToken)
{
var action = new CreateOrderAction(request.CustomerId, request.Items);
var result = await _dispatcher.DispatchAsync(action, cancellationToken);

if (result.IsSuccess)
return Ok();

return BadRequest(result.ErrorMessage);
}
}
Production Ready

The setup above is a complete, production-ready Dispatch application. Everything below describes optional capabilities you can add later. For a laser-focused guide, see Dispatch Only.

Optional Capabilities

Add these if and when you need them — each is independent and opt-in:

  • Domain modeling — Add Excalibur.Domain if you need aggregates, entities, and value objects
  • Event sourcing — Add Excalibur.EventSourcing.* if you need event replay, snapshots, and audit trails
  • Workflows — Add Excalibur.Saga.* if you need multi-step orchestrated processes
  • Unified builder — Add Excalibur.Hosting if you want a single AddExcalibur() entry point for all subsystems

Because all packages share the same Excalibur.* namespace, you never rewrite existing code when adding new capabilities.

Complete Package Reference (70+ packages)

Package Overview

Core Packages

PackageDescription
Excalibur.DispatchCore dispatcher, pipelines, middleware
Excalibur.Dispatch.AbstractionsPublic interfaces (IDispatchAction, IDispatcher)

Transport Packages

PackageDescription
Excalibur.Dispatch.Transport.KafkaApache Kafka transport
Excalibur.Dispatch.Transport.RabbitMQRabbitMQ transport
Excalibur.Dispatch.Transport.AzureServiceBusAzure Service Bus transport
Excalibur.Dispatch.Transport.AwsSqsAWS SQS transport
Excalibur.Dispatch.Transport.GooglePubSubGoogle Pub/Sub transport

Hosting Packages

PackageDescription
Excalibur.Dispatch.Hosting.AspNetCoreASP.NET Core integration
Excalibur.Dispatch.Hosting.AzureFunctionsAzure Functions hosting
Excalibur.Dispatch.Hosting.AwsLambdaAWS Lambda hosting
Excalibur.Dispatch.Hosting.GoogleCloudFunctionsGoogle Cloud Functions hosting
Excalibur.Dispatch.Hosting.Serverless.AbstractionsServerless abstractions

Serialization Packages

PackageDescription
Excalibur.Dispatch.Serialization.MemoryPackHigh-performance binary serialization (opt-in)
Excalibur.Dispatch.Serialization.MessagePackMessagePack serialization
Excalibur.Dispatch.Serialization.ProtobufProtocol Buffers serialization

Security & Compliance Packages

PackageDescription
Excalibur.SecurityCore security infrastructure
Excalibur.AuditLoggingComprehensive audit logging
Excalibur.AuditLogging.DatadogDatadog audit export
Excalibur.AuditLogging.SentinelAzure Sentinel integration
Excalibur.AuditLogging.SplunkSplunk audit export
Excalibur.AuditLogging.SqlServerSQL Server audit store
Excalibur.ComplianceRegulatory compliance framework
Excalibur.Compliance.AbstractionsCompliance abstractions
Excalibur.Compliance.AwsAWS compliance integration
Excalibur.Compliance.AzureAzure compliance integration
Excalibur.Compliance.VaultHashiCorp Vault integration

Operations Packages

PackageDescription
Excalibur.Dispatch.ObservabilityOpenTelemetry integration
Excalibur.Dispatch.Resilience.PollyPolly integration for resilience
Excalibur.Dispatch.CachingCaching infrastructure
Excalibur.Dispatch.Validation.FluentValidationFluentValidation integration

Patterns Packages

PackageDescription
Excalibur.Dispatch.PatternsMessaging patterns (Outbox, ClaimCheck, etc.)
Excalibur.Dispatch.Patterns.AzureAzure-specific patterns
Excalibur.Dispatch.Patterns.ClaimCheck.InMemoryIn-memory claim check store
Excalibur.Dispatch.Patterns.Hosting.JsonJSON hosting patterns

Tooling Packages

PackageDescription
Excalibur.Dispatch.AnalyzersRoslyn analyzers
Excalibur.Dispatch.SourceGeneratorsSource generators
Excalibur.Dispatch.LeaderElection.AbstractionsLeader election abstractions

Next Steps

See Also