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<string> DescribeAuditTrailAsync(IAuditQuery audit, CancellationToken ct)
{
AuditIntegrityResult result = await audit.VerifyChainIntegrityAsync(
startDate: DateTimeOffset.UtcNow.AddDays(-30),
endDate: DateTimeOffset.UtcNow,
cancellationToken: ct);

return result.Outcome switch
{
AuditIntegrityOutcome.Verified
=> $"Intact: {result.EventsVerified} events checked.",

AuditIntegrityOutcome.ViolationsDetected
=> $"Tampered at {result.FirstViolationEventId}: {result.ViolationDescription}",

// The window held no audit events, so nothing was checked and nothing is proven.
// This is deliberately a separate outcome: it must never be reported as a pass.
_ => "Not exercised: no audit events in this window.",
};
}

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.Succeeded)
return Ok();

return Problem(result.ErrorMessage, statusCode: result.ProblemDetails?.Status);
}
}
Do not map a failed result to 400

A failed IMessageResult means your handler ran and reported a failure — not, by default, that the caller sent a bad request. Hard-coding BadRequest(...) reports a server-side fault to the caller as their own mistake, so they retry a request that can never succeed, or abandon one that would have.

result.ProblemDetails.Status carries the status the framework determined for that failure. With the pipeline's exception mapping configured (UseExceptionMapping()), a validation failure arrives as 400 and an authorization failure as 403; a handler that threw with nothing mapping it arrives as 500. When no status was determined, ProblemDetails is null and Problem(...) falls back to 500 — the safe direction, and never the caller's fault by accident.

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.LeaderElection.AbstractionsLeader election abstractions

Next Steps​

See Also​