Skip to content

A modern C# functional result type with structured errors, async workflows, LINQ support, and deconstruction

License

Notifications You must be signed in to change notification settings

JeanMarcMbouma/Outcome

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

157 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

BbQ Libraries - Functional Result Types, CQRS & Events

A comprehensive suite of modern C# libraries for functional error handling, command-query responsibility segregation, and event-driven architecture patterns.

πŸ“¦ Packages

A modern C# functional result type for error-aware programming.

  • Structured errors with Code, Description, and Severity
  • Async composition with BindAsync, MapAsync, CombineAsync
  • LINQ integration with native Select/SelectMany support
  • Source generator support for auto-generating error helpers
  • Multi-targeting across netstandard2.0, net6.0, and net8.0
dotnet add package BbQ.Outcome

πŸ“– Full Documentation πŸ“–

A lightweight, extensible CQRS implementation that integrates seamlessly with Outcome.

  • Type-safe mediator for commands and queries
  • Unified pipeline behaviors for both regular and streaming requests
  • Streaming handlers for processing large datasets with IAsyncEnumerable<T>
  • Specialized dispatchers (ICommandDispatcher, IQueryDispatcher) for explicit CQRS separation
  • Source generators for automatic handler registration, behavior registration
  • Test utilities with TestMediator and StubHandler
  • Comprehensive documentation on all interfaces and classes
  • Seamless integration with Outcome<T> for error handling
dotnet add package BbQ.Cqrs

πŸ“– Full Documentation πŸ“–

Event-driven architecture support with strongly-typed pub/sub patterns.

  • Type-safe event publishing with IEventPublisher
  • Event handlers (IEventHandler<TEvent>) for processing events one-by-one
  • Event subscribers (IEventSubscriber<TEvent>) for consuming event streams
  • In-memory event bus for single-process applications
  • Thread-safe implementation using System.Threading.Channels
  • Storage-agnostic design - extend for distributed scenarios
  • Source generator support - automatic handler/subscriber discovery
  • Fully independent - works standalone or with BbQ.Cqrs
dotnet add package BbQ.Events

πŸ“– Full Documentation πŸ“–

πŸš€ Quick Start

Using Outcome

var result = await GetUserAsync(userId);

return result.Match(
    onSuccess: user => Ok(user),
    onError: errors => BadRequest(new { errors })
);

Using Outcome + CQRS

// Define error codes
[QbqOutcome]
public enum UserErrorCode
{
    [Description("User not found")]
    NotFound,
    [Description("Email already in use")]
    EmailAlreadyExists
}

// Define a command
public class CreateUserCommand : ICommand<Outcome<User>>
{
    public string Email { get; set; }
    public string Name { get; set; }
}

// Implement a handler
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, Outcome<User>>
{
    public async Task<Outcome<User>> Handle(CreateUserCommand request, CancellationToken ct)
    {
        // Implementation...
    }
}

// Register and use
services.AddBbQMediator(typeof(Program).Assembly);

var result = await mediator.Send(new CreateUserCommand { Email = "test@example.com", Name = "Test" });

Using Events

// Register event bus
services.AddInMemoryEventBus();
services.AddYourAssemblyEventHandlers(); // Auto-discovers handlers

// Define an event
public record UserCreated(Guid Id, string Name);

// Publish event
await eventPublisher.Publish(new UserCreated(userId, userName));

// Handle event (auto-discovered)
public class SendWelcomeEmailHandler : IEventHandler<UserCreated>
{
    public Task Handle(UserCreated @event, CancellationToken ct)
    {
        // Send email...
        return Task.CompletedTask;
    }
}

πŸ’Ύ Installation

# Core error handling
dotnet add package BbQ.Outcome

# CQRS pattern support
dotnet add package BbQ.Cqrs

# Event-driven architecture
dotnet add package BbQ.Events

πŸ”— Integration

These libraries work best together:

// Error codes are auto-generated with source generator
[QbqOutcome]
public enum DomainErrors
{
    [Description("Invalid input")]
    [ErrorSeverity(ErrorSeverity.Validation)]
    ValidationFailed,

    [Description("Not found")]
    NotFound
}

// Commands/queries return Outcome<T>
public class GetUserQuery : IQuery<Outcome<User>> { }

// Handlers use auto-generated errors
public class GetUserQueryHandler : IRequestHandler<GetUserQuery, Outcome<User>>
{
    public async Task<Outcome<User>> Handle(GetUserQuery request, CancellationToken ct)
    {
        var user = await _repository.GetAsync(request.UserId);
        return user == null 
            ? DomainErrorsErrors.NotFoundError.ToOutcome<User>()
            : Outcome<User>.From(user);
    }
}

✨ Key Features

Feature Outcome CQRS Events
Structured error handling βœ… βœ… -
Async composition βœ… βœ… βœ…
Source-generated helpers βœ… βœ… βœ…
LINQ integration βœ… - -
Mediator pattern - βœ… -
Pipeline behaviors - βœ… -
Streaming handlers - βœ… βœ…
Type-safe commands/queries - βœ… -
Event publishing - - βœ…
Event handlers - - βœ…
Event subscribers - - βœ…
Thread-safe in-memory bus - - βœ…
Storage-agnostic design - - βœ…
Fully independent βœ… βœ… βœ…
Test utilities - βœ… -

πŸ“š Documentation

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

About

A modern C# functional result type with structured errors, async workflows, LINQ support, and deconstruction

Resources

License

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages