Skip to main content

Package Guide

Excalibur is one framework with focused package families. Install only what your application needs — every package beyond Excalibur.Dispatch is optional.

Quick Summary

Package FamilyPurposeWhen to Add
Excalibur.Dispatch.*Messaging, pipeline, handlers, transportsAlways — this is the foundation
Excalibur.DomainAggregates, entities, value objectsWhen you need rich domain modeling
Excalibur.EventSourcing.*Event stores, snapshots, persistenceWhen you need event sourcing
Excalibur.Saga.*Sagas and process managersWhen you need long-running workflows
Excalibur.Hosting.*ASP.NET Core, serverless hostingWhen you need opinionated hosting templates
Excalibur.LeaderElection.*Distributed coordinationWhen you need single-leader guarantees
Key Rule

All packages share the Excalibur.* namespace. You never rewrite existing code when adding new capabilities — just install additional packages.


Decision Flowchart

flowchart TD
A[Start] --> B{Need message<br/>dispatching?}
B -->|Yes| C[Install Excalibur.Dispatch]
C --> D{Need domain<br/>modeling?}
D -->|No| E[Excalibur.Dispatch only]
D -->|Yes| F[Add Excalibur.Domain]
F --> G{Need event<br/>sourcing?}
G -->|No| H[Dispatch + Domain]
G -->|Yes| I[Add Excalibur.EventSourcing.*]
I --> J{Need sagas/<br/>process managers?}
J -->|No| K[Event Sourcing Stack]
J -->|Yes| L[Add Excalibur.Saga.*]
L --> M[Full Stack]

Scenario-Based Package Selection

If You're Building...Install These
Simple API with handlers (MediatR replacement)Excalibur.Dispatch, Excalibur.Dispatch.Abstractions
Message-driven microservices with Kafka+ Excalibur.Dispatch.Transport.Kafka
DDD application with aggregates+ Excalibur.Domain
Event-sourced system+ Excalibur.EventSourcing, Excalibur.EventSourcing.SqlServer
CQRS with projections+ Excalibur.Caching
Long-running workflows+ Excalibur.Saga, Excalibur.Saga.SqlServer
Azure Functions serverlessExcalibur.Dispatch.Hosting.AzureFunctions
AWS Lambda serverlessExcalibur.Dispatch.Hosting.AwsLambda
Production ASP.NET Core app+ Excalibur.Hosting.Web
SOC2/GDPR compliant system+ Excalibur.Dispatch.Compliance.*, Excalibur.Dispatch.AuditLogging.*

Hosting Packages

Deployment ModelPackageNotes
Console AppExcalibur.DispatchMinimal
ASP.NET CoreExcalibur.Dispatch.Hosting.AspNetCore + Excalibur.Hosting.WebFull hosting
Worker ServiceExcalibur.Dispatch + Excalibur.HostingBackground jobs
Azure FunctionsExcalibur.Dispatch.Hosting.AzureFunctionsServerless
AWS LambdaExcalibur.Dispatch.Hosting.AwsLambdaServerless
Google Cloud FunctionsExcalibur.Dispatch.Hosting.GoogleCloudFunctionsServerless

Compliance & Audit Packages

PackagePurpose
Excalibur.Dispatch.Compliance.*Compliance scanning, audit trail
Excalibur.Dispatch.AuditLogging.DatadogDatadog SIEM integration
Excalibur.Dispatch.AuditLogging.SentinelMicrosoft Sentinel integration
Excalibur.Dispatch.AuditLogging.SplunkSplunk integration
Excalibur.Compliance.SqlServerKey escrow persistence

Gradual Adoption Path

Phase 1: Messaging (MediatR Replacement)

dotnet add package Excalibur.Dispatch
dotnet add package Excalibur.Dispatch.Abstractions
// Program.cs
services.AddDispatch(dispatch =>
{
dispatch.AddHandlersFromAssembly(typeof(Program).Assembly);
});
// Define action
public record CreateOrderAction(string CustomerId, decimal Amount) : IDispatchAction;

// Define handler
public class CreateOrderHandler : IActionHandler<CreateOrderAction>
{
public async Task HandleAsync(CreateOrderAction action, CancellationToken ct)
{
// Business logic
}
}

// Dispatch
await dispatcher.DispatchAsync(new CreateOrderAction("cust-123", 99.99m), ct);

This alone replaces MediatR.


Phase 2: Add Domain Modeling

When you need rich domain models with aggregates:

dotnet add package Excalibur.Domain
public class Order : AggregateRoot<Guid>
{
public OrderStatus Status { get; private set; }

public static Order Create(string customerId, decimal amount)
{
var order = new Order();
order.RaiseEvent(new OrderCreatedEvent(Guid.NewGuid(), customerId, amount));
return order;
}

public void Confirm()
{
if (Status != OrderStatus.Pending)
throw new InvalidOperationException("Order must be pending");
RaiseEvent(new OrderConfirmedEvent(Id));
}

protected override void ApplyEventInternal(IDomainEvent @event) => _ = @event switch
{
OrderCreatedEvent e => ApplyEvent(e),
OrderConfirmedEvent e => ApplyEvent(e),
_ => false
};

private bool ApplyEvent(OrderCreatedEvent e) { Id = e.OrderId; Status = OrderStatus.Pending; return true; }
private bool ApplyEvent(OrderConfirmedEvent e) { Status = OrderStatus.Confirmed; return true; }
}

Phase 3: Add Event Sourcing

When you need to persist events and rebuild state:

dotnet add package Excalibur.EventSourcing
dotnet add package Excalibur.EventSourcing.SqlServer
dotnet add package Excalibur.Hosting
// Program.cs — sensible defaults
services.AddExcalibur(excalibur =>
{
excalibur.AddEventSourcing(es => es.UseEventStore<SqlServerEventStore>());
});

Need transports or custom pipelines? Call AddDispatch with a builder action:

// Program.cs — with custom messaging configuration
services.AddDispatch(dispatch =>
{
dispatch.AddHandlersFromAssembly(typeof(Program).Assembly);
dispatch.UseRabbitMQ(rmq => rmq.HostName("localhost"));
});

services.AddExcalibur(excalibur =>
{
excalibur.AddEventSourcing(es => es.UseEventStore<SqlServerEventStore>());
});
// In handler
public class ConfirmOrderHandler : IActionHandler<ConfirmOrderAction>
{
private readonly IEventSourcedRepository<Order> _repository;

public ConfirmOrderHandler(IEventSourcedRepository<Order> repository)
{
_repository = repository;
}

public async Task HandleAsync(ConfirmOrderAction action, CancellationToken ct)
{
var order = await _repository.GetByIdAsync(action.OrderId, ct);
order.Confirm();
await _repository.SaveAsync(order, ct);
}
}

Phase 4: Full Stack

Add sagas, hosting templates, and compliance as needed:

dotnet add package Excalibur.Hosting.Web
dotnet add package Excalibur.Saga
dotnet add package Excalibur.Saga.SqlServer
services.AddDispatch(dispatch =>
{
dispatch.AddHandlersFromAssembly(typeof(Program).Assembly);
dispatch.UseRabbitMQ(rmq => rmq.HostName("localhost"));
dispatch.AddObservability();
dispatch.AddResilience(res => res.DefaultRetryCount = 3);
});

services.AddExcalibur(excalibur =>
{
excalibur
.AddEventSourcing(es => es.UseEventStore<SqlServerEventStore>())
.AddOutbox(outbox => outbox.UseSqlServer(connectionString))
.AddSagas(opts => opts.EnableTimeouts = true)
.AddLeaderElection(opts => opts.LeaseDuration = TimeSpan.FromSeconds(30));
});

Package Ownership by Family

Excalibur.Dispatch (Messaging)

CategoryPackageExamples
Message dispatchingExcalibur.DispatchIDispatcher, DispatchAsync()
Message contractsExcalibur.Dispatch.AbstractionsIDomainEvent, IDispatchAction
PipelineExcalibur.DispatchIDispatchMiddleware
HandlersExcalibur.Dispatch.AbstractionsIActionHandler<T>, IEventHandler<T>
ContextExcalibur.DispatchMessageContext, correlation
SerializationExcalibur.Dispatch.Serialization.*MemoryPack, MessagePack
TransportsExcalibur.Dispatch.Transport.*Kafka, RabbitMQ, Azure Service Bus
ObservabilityExcalibur.Dispatch.ObservabilityMetrics, tracing
ComplianceExcalibur.Dispatch.Compliance.*Audit logging, SIEM

Excalibur (Domain & Persistence)

CategoryPackageExamples
Domain modelingExcalibur.DomainAggregateRoot<T>, Entity<T>
Event sourcingExcalibur.EventSourcingIEventStore, ISnapshotStore
SQL Server persistenceExcalibur.EventSourcing.SqlServerEvent store implementation
Data accessExcalibur.Data.AbstractionsIDataRequest, IDb
SagasExcalibur.Saga.*Process managers, orchestration
HostingExcalibur.Hosting.*Web, Worker templates
Leader electionExcalibur.LeaderElection.*Distributed coordination
CachingExcalibur.CachingProjection invalidation

Common Questions

Can I use Excalibur.Dispatch without the other packages?

Yes! Excalibur.Dispatch is completely standalone. Use it as a MediatR replacement with zero additional dependencies.

Do I need multiple packages for event sourcing?

Yes. Excalibur.Dispatch provides the message contracts (IDomainEvent), Excalibur.Domain provides aggregates, and Excalibur.EventSourcing provides the persistence (IEventStore).

Which hosting package for serverless?

Use the serverless hosting packages (Excalibur.Dispatch.Hosting.AzureFunctions, Excalibur.Dispatch.Hosting.AwsLambda). They don't need the full hosting stack.

Where do compliance features live?

In the Excalibur.Dispatch.Compliance.* and Excalibur.Dispatch.AuditLogging.* packages.


See Also