Dispatchly 1.0.5
dotnet add package Dispatchly --version 1.0.5
NuGet\Install-Package Dispatchly -Version 1.0.5
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Dispatchly" Version="1.0.5" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Dispatchly" Version="1.0.5" />
<PackageReference Include="Dispatchly" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Dispatchly --version 1.0.5
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Dispatchly, 1.0.5"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Dispatchly@1.0.5
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Dispatchly&version=1.0.5
#tool nuget:?package=Dispatchly&version=1.0.5
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Dispatchly
A lightweight, delegate-based CQRS framework for .NET that provides command/query separation with pipeline behaviors and notification support.
Features
- ✅ Delegate-based: Uses delegates instead of reflection for better performance
- ✅ Thread-safe: Built with
ConcurrentDictionary
andConcurrentBag
for thread safety - ✅ Pipeline Behaviors: Support for cross-cutting concerns like logging, validation, caching
- ✅ Notifications: Publish/subscribe pattern for domain events
- ✅ Cancellation Support: Full
CancellationToken
support throughout - ✅ Production Ready: Comprehensive error handling, validation, and disposal patterns
- ✅ XML Documentation: Complete API documentation
- ✅ Nullable Reference Types: Full null safety support
Quick Start
Installation
dotnet add package Dispatchly
Basic Usage
using Dispatchly;
// Create dispatcher
var dispatcher = new Dispatcher();
// Register command handler
dispatcher.RegisterCommandHandler<CreateUserCommand>(async (command, cancellationToken) =>
{
// Handle the command
await CreateUserAsync(command, cancellationToken);
});
// Register query handler
dispatcher.RegisterQueryHandler<GetUserQuery, User>(async (query, cancellationToken) =>
{
// Handle the query
return await GetUserAsync(query.UserId, cancellationToken);
});
// Send a command
await dispatcher.Send(new CreateUserCommand { Name = "John", Email = "john@example.com" });
// Execute a query
var user = await dispatcher.Query(new GetUserQuery { UserId = 123 });
Advanced Usage
Pipeline Behaviors
// Logging behavior
dispatcher.UseCommandBehavior<CreateUserCommand>(async (command, next, cancellationToken) =>
{
Console.WriteLine($"Executing command: {command.GetType().Name}");
try
{
await next();
Console.WriteLine("Command executed successfully");
}
catch (Exception ex)
{
Console.WriteLine($"Command failed: {ex.Message}");
throw;
}
});
// Validation behavior
dispatcher.UseQueryBehavior<GetUserQuery, User>(async (query, next, cancellationToken) =>
{
if (query.UserId <= 0)
throw new ArgumentException("User ID must be positive");
return await next();
});
Notifications
// Register notification handlers
dispatcher.RegisterNotificationHandler<UserCreatedEvent>(async (notification, cancellationToken) =>
{
await SendWelcomeEmailAsync(notification.UserId, cancellationToken);
});
dispatcher.RegisterNotificationHandler<UserCreatedEvent>(async (notification, cancellationToken) =>
{
await UpdateAuditLogAsync(notification, cancellationToken);
});
// Publish notification (multiple handlers will execute)
await dispatcher.Publish(new UserCreatedEvent { UserId = 123, Name = "John" });
Error Handling
try
{
await dispatcher.Send(new CreateUserCommand { Name = "John" });
}
catch (HandlerNotFoundException ex)
{
Console.WriteLine($"No handler found for {ex.MessageType.Name}");
}
catch (ArgumentNullException ex)
{
Console.WriteLine($"Null argument: {ex.ParamName}");
}
API Reference
Core Interfaces
ICommand
- Marker interface for commandsIQuery<TResult>
- Marker interface for queriesINotification
- Marker interface for notifications
Delegates
CommandHandlerDelegate<TCommand>
- Handles commandsQueryHandlerDelegate<TQuery, TResult>
- Handles queriesCommandPipelineDelegate<TCommand>
- Command pipeline behaviorQueryPipelineDelegate<TQuery, TResult>
- Query pipeline behaviorNotificationHandlerDelegate<TNotification>
- Handles notifications
Dispatcher Methods
RegisterCommandHandler<TCommand>()
- Register command handlerRegisterQueryHandler<TQuery, TResult>()
- Register query handlerRegisterNotificationHandler<TNotification>()
- Register notification handlerUseCommandBehavior<TCommand>()
- Add command pipeline behaviorUseQueryBehavior<TQuery, TResult>()
- Add query pipeline behaviorSend<TCommand>()
- Send commandQuery<TQuery, TResult>()
- Execute queryPublish<TNotification>()
- Publish notificationHasCommandHandler<TCommand>()
- Check if command handler existsHasQueryHandler<TQuery>()
- Check if query handler existsHasNotificationHandlers<TNotification>()
- Check if notification handlers exist
Properties
CommandHandlerCount
- Number of registered command handlersQueryHandlerCount
- Number of registered query handlersNotificationHandlerCount
- Number of registered notification handlersCommandBehaviorCount
- Number of registered command behaviorsQueryBehaviorCount
- Number of registered query behaviors
Best Practices
1. Use Dependency Injection
services.AddSingleton<Dispatcher>();
2. Implement Proper Error Handling
public async Task<Result<User>> CreateUserAsync(CreateUserCommand command)
{
try
{
await _dispatcher.Send(command);
return Result<User>.Success();
}
catch (HandlerNotFoundException)
{
return Result<User>.Failure("Handler not configured");
}
catch (Exception ex)
{
return Result<User>.Failure(ex.Message);
}
}
3. Use Cancellation Tokens
public async Task<User> GetUserAsync(int userId, CancellationToken cancellationToken = default)
{
return await _dispatcher.Query(new GetUserQuery { UserId = userId }, cancellationToken);
}
4. Implement Pipeline Behaviors for Cross-cutting Concerns
// Logging
dispatcher.UseCommandBehavior<CreateUserCommand>(async (command, next, cancellationToken) =>
{
_logger.LogInformation("Executing {CommandType}", command.GetType().Name);
await next();
_logger.LogInformation("Executed {CommandType}", command.GetType().Name);
});
// Validation
dispatcher.UseCommandBehavior<CreateUserCommand>(async (command, next, cancellationToken) =>
{
var validator = new CreateUserCommandValidator();
var result = await validator.ValidateAsync(command, cancellationToken);
if (!result.IsValid)
throw new ValidationException(result.Errors);
await next();
});
5. Proper Disposal
public class MyService : IDisposable
{
private readonly Dispatcher _dispatcher;
public MyService(Dispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public void Dispose()
{
_dispatcher?.Dispose();
}
}
Performance Considerations
- Delegate-based: No reflection overhead
- Thread-safe: Concurrent collections for high-performance scenarios
- Memory efficient: Proper disposal patterns
- Async/await: Full async support throughout
License
MIT License - see LICENSE file for details.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. 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. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.