{"id":28619070,"url":"https://github.com/loresoft/arbiter","last_synced_at":"2026-04-01T20:02:43.211Z","repository":{"id":287257814,"uuid":"964003921","full_name":"loresoft/Arbiter","owner":"loresoft","description":"Mediator pattern and Command Query Responsibility Segregation (CQRS) implementation in .NET","archived":false,"fork":false,"pushed_at":"2026-01-30T18:36:37.000Z","size":1888,"stargazers_count":18,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-01-31T11:45:22.782Z","etag":null,"topics":["cqrs","entity-framework-core","mediator","mediator-pattern","mongodb"],"latest_commit_sha":null,"homepage":"http://loresoft.com/Arbiter/","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/loresoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"loresoft"}},"created_at":"2025-04-10T14:41:10.000Z","updated_at":"2026-01-30T18:20:28.000Z","dependencies_parsed_at":null,"dependency_job_id":"9825886f-0301-4093-b013-e0769470cce4","html_url":"https://github.com/loresoft/Arbiter","commit_stats":null,"previous_names":["loresoft/arbiter"],"tags_count":64,"template":false,"template_full_name":null,"purl":"pkg:github/loresoft/Arbiter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loresoft%2FArbiter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loresoft%2FArbiter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loresoft%2FArbiter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loresoft%2FArbiter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/loresoft","download_url":"https://codeload.github.com/loresoft/Arbiter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loresoft%2FArbiter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29218735,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T02:25:35.815Z","status":"ssl_error","status_checked_at":"2026-02-08T02:24:27.970Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cqrs","entity-framework-core","mediator","mediator-pattern","mongodb"],"created_at":"2025-06-12T04:20:20.014Z","updated_at":"2026-04-01T20:02:43.150Z","avatar_url":"https://github.com/loresoft.png","language":"C#","readme":"# Arbiter\n\n**A powerful, lightweight, and extensible implementation of the Mediator pattern and Command Query Responsibility Segregation (CQRS) for .NET applications.**\n\nArbiter is designed for building clean, modular architectures like Vertical Slice Architecture and CQRS. It provides a comprehensive suite of libraries that work together to simplify complex application patterns while maintaining high performance and flexibility.\n\n[![Build Status](https://github.com/loresoft/Arbiter/actions/workflows/dotnet.yml/badge.svg)](https://github.com/loresoft/Arbiter/actions)\n[![License](https://img.shields.io/github/license/loresoft/Arbiter.svg)](LICENSE)\n\n## Key Features\n\n- **Clean Architecture**: Perfect for Vertical Slice Architecture and CQRS patterns\n- **High Performance**: Minimal overhead with efficient mediator implementation\n- **Extensible**: Pipeline behaviors, custom handlers, and extensive customization options\n- **Observable**: Built-in OpenTelemetry support for tracing and metrics\n- **Database Agnostic**: Support for Entity Framework Core, MongoDB, and more\n- **Web Ready**: Minimal API endpoints and MVC controller support\n- **Communication**: Integrated email and SMS messaging capabilities\n- **Blazor Ready**: First-class Dispatcher support for Blazor Auto, Server Interactive, and WebAssembly render modes\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Packages](#packages)\n- [Core Libraries](#core-libraries)\n  - [Arbiter.Mediation](#arbitermediation)\n  - [Arbiter.CommandQuery](#arbitercommandquery)\n  - [Arbiter.Mapping](#arbitermapping)\n  - [Arbiter.Services](#arbiterservices)\n  - [Arbiter.Communication](#arbitercommunication)\n- [Data Providers](#data-providers)\n- [Web Integration](#web-integration)\n- [Blazor Dispatcher](#blazor-dispatcher)\n- [Documentation](#documentation)\n- [Samples](#samples)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Quick Start\n\nGet started with Arbiter in just a few steps:\n\n### 1. Install the Core Package\n\n```bash\ndotnet add package Arbiter.Mediation\n```\n\n### 2. Define a Request and Handler\n\n```csharp\n// Define your request\npublic class GetUserQuery : IRequest\u003cUser\u003e\n{\n    public int UserId { get; set; }\n}\n\n// Implement the handler\npublic class GetUserHandler : IRequestHandler\u003cGetUserQuery, User\u003e\n{\n    public async ValueTask\u003cUser?\u003e Handle(GetUserQuery request, CancellationToken cancellationToken)\n    {\n        // Your business logic here\n        return await GetUserFromDatabase(request.UserId);\n    }\n}\n```\n\n### 3. Register Services\n\n```csharp\nservices.AddMediator();\nservices.AddTransient\u003cIRequestHandler\u003cGetUserQuery, User\u003e, GetUserHandler\u003e();\n```\n\n### 4. Use the Mediator\n\n```csharp\npublic class UserController : ControllerBase\n{\n    private readonly IMediator _mediator;\n\n    public UserController(IMediator mediator) =\u003e _mediator = mediator;\n\n    [HttpGet(\"{id}\")]\n    public async Task\u003cUser\u003e GetUser(int id)\n    {\n        return await _mediator.Send(new GetUserQuery { UserId = id });\n    }\n}\n```\n\n## Packages\n\n### Core Libraries Packages\n\n| Library                                        | Package                                                                                                                                     | Description                                                       |\n| :--------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------ | :---------------------------------------------------------------- |\n| [Arbiter.Mediation](#arbitermediation)         | [![Arbiter.Mediation](https://img.shields.io/nuget/v/Arbiter.Mediation.svg)](https://www.nuget.org/packages/Arbiter.Mediation/)             | Lightweight and extensible implementation of the Mediator pattern |\n| [Arbiter.CommandQuery](#arbitercommandquery)   | [![Arbiter.CommandQuery](https://img.shields.io/nuget/v/Arbiter.CommandQuery.svg)](https://www.nuget.org/packages/Arbiter.CommandQuery/)    | Base package for Commands, Queries and Behaviors                  |\n| [Arbiter.Mapping](#arbitermapping)             | [![Arbiter.Mapping](https://img.shields.io/nuget/v/Arbiter.Mapping.svg)](https://www.nuget.org/packages/Arbiter.Mapping/)                   | Source-generated, compile-time object mapping                     |\n| [Arbiter.Services](#arbiterservices)           | [![Arbiter.Services](https://img.shields.io/nuget/v/Arbiter.Services.svg)](https://www.nuget.org/packages/Arbiter.Services/)                | Utility services for CSV, encryption, caching, and tokens         |\n| [Arbiter.Communication](#arbitercommunication) | [![Arbiter.Communication](https://img.shields.io/nuget/v/Arbiter.Communication.svg)](https://www.nuget.org/packages/Arbiter.Communication/) | Message template communication for email and SMS services         |\n\n### Data Providers Packages\n\n| Library                                                                     | Package                                                                                                                                                                                  | Description                                                      |\n| :-------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------- |\n| [Arbiter.CommandQuery.EntityFramework](#arbitercommandqueryentityframework) | [![Arbiter.CommandQuery.EntityFramework](https://img.shields.io/nuget/v/Arbiter.CommandQuery.EntityFramework.svg)](https://www.nuget.org/packages/Arbiter.CommandQuery.EntityFramework/) | Entity Framework Core handlers for the base Commands and Queries |\n| [Arbiter.CommandQuery.MongoDB](#arbitercommandquerymongodb)                 | [![Arbiter.CommandQuery.MongoDB](https://img.shields.io/nuget/v/Arbiter.CommandQuery.MongoDB.svg)](https://www.nuget.org/packages/Arbiter.CommandQuery.MongoDB/)                         | MongoDB handlers for the base Commands and Queries               |\n\n### Web Integration Packages\n\n| Library                                                         | Package                                                                                                                                                                | Description                                         |\n| :-------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------- |\n| [Arbiter.CommandQuery.Endpoints](#arbitercommandqueryendpoints) | [![Arbiter.CommandQuery.Endpoints](https://img.shields.io/nuget/v/Arbiter.CommandQuery.Endpoints.svg)](https://www.nuget.org/packages/Arbiter.CommandQuery.Endpoints/) | Minimal API endpoints for base Commands and Queries |\n| [Arbiter.CommandQuery.Mvc](#arbitercommandquerymvc)             | [![Arbiter.CommandQuery.Mvc](https://img.shields.io/nuget/v/Arbiter.CommandQuery.Mvc.svg)](https://www.nuget.org/packages/Arbiter.CommandQuery.Mvc/)                   | MVC Controllers for base Commands and Queries       |\n\n### Blazor Dispatcher Packages\n\n| Library                                               | Package                                                                                                                                                 | Description                                                                      |\n| :---------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------- |\n| [Arbiter.Dispatcher.Server](#arbiterdispatcherserver) | [![Arbiter.Dispatcher.Server](https://img.shields.io/nuget/v/Arbiter.Dispatcher.Server.svg)](https://www.nuget.org/packages/Arbiter.Dispatcher.Server/) | ASP.NET Core endpoint that receives dispatcher messages from Blazor WASM clients |\n| [Arbiter.Dispatcher.Client](#arbiterdispatcherclient) | [![Arbiter.Dispatcher.Client](https://img.shields.io/nuget/v/Arbiter.Dispatcher.Client.svg)](https://www.nuget.org/packages/Arbiter.Dispatcher.Client/) | Client-side dispatcher for Blazor: JSON/MessagePack (WASM) and ServerDispatcher  |\n\n### Communication Providers Packages\n\n| Library                                                     | Package                                                                                                                                                          | Description                                                   |\n| :---------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------ |\n| [Arbiter.Communication.Azure](#arbitercommunicationazure)   | [![Arbiter.Communication.Azure](https://img.shields.io/nuget/v/Arbiter.Communication.Azure.svg)](https://www.nuget.org/packages/Arbiter.Communication.Azure/)    | Communication implementation for Azure Communication Services |\n| [Arbiter.Communication.Twilio](#arbitercommunicationtwilio) | [![Arbiter.Communication.Twilio](https://img.shields.io/nuget/v/Arbiter.Communication.Twilio.svg)](https://www.nuget.org/packages/Arbiter.Communication.Twilio/) | Communication implementation for SendGrid and Twilio          |\n\n## Core Libraries\n\n### Arbiter.Mediation\n\nA lightweight and extensible implementation of the Mediator pattern for .NET applications, designed for clean, modular architectures like Vertical Slice Architecture and CQRS.\n\n#### Mediation Features\n\n- **Request/Response Pattern**: Handle requests with typed responses using `IRequest\u003cTResponse\u003e` and `IRequestHandler\u003cTRequest, TResponse\u003e`\n- **Notifications/Events**: Publish events using `INotification` and `INotificationHandler\u003cTNotification\u003e`\n- **Pipeline Behaviors**: Middleware-like cross-cutting concerns using `IPipelineBehavior\u003cTRequest, TResponse\u003e`\n- **Dependency Injection**: Seamless integration with .NET's DI container\n- **High Performance**: Minimal allocations and efficient execution\n- **OpenTelemetry Ready**: Built-in observability support\n\n#### Installation\n\n```bash\ndotnet add package Arbiter.Mediation\n```\n\n#### Basic Usage\n\n**1. Define Request and Response**\n\n```csharp\npublic class Ping : IRequest\u003cPong\u003e\n{\n    public string? Message { get; set; }\n}\n\npublic class Pong\n{\n    public string? Message { get; set; }\n}\n```\n\n**2. Implement Handler**\n\n```csharp\npublic class PingHandler : IRequestHandler\u003cPing, Pong\u003e\n{\n    public async ValueTask\u003cPong?\u003e Handle(\n        Ping request,\n        CancellationToken cancellationToken = default)\n    {\n        // Simulate async work\n        await Task.Delay(100, cancellationToken);\n\n        return new Pong { Message = $\"{request.Message} Pong\" };\n    }\n}\n```\n\n**3. Define Pipeline Behavior (Optional)**\n\n```csharp\npublic class LoggingBehavior\u003cTRequest, TResponse\u003e : IPipelineBehavior\u003cTRequest, TResponse\u003e\n    where TRequest : IRequest\u003cTResponse\u003e\n{\n    private readonly ILogger\u003cLoggingBehavior\u003cTRequest, TResponse\u003e\u003e _logger;\n\n    public LoggingBehavior(ILogger\u003cLoggingBehavior\u003cTRequest, TResponse\u003e\u003e logger)\n    {\n        _logger = logger;\n    }\n\n    public async ValueTask\u003cTResponse\u003e Handle(\n        TRequest request,\n        RequestHandlerDelegate\u003cTResponse\u003e next,\n        CancellationToken cancellationToken = default)\n    {\n        _logger.LogInformation(\"Handling {RequestType}\", typeof(TRequest).Name);\n        \n        var response = await next(cancellationToken);\n        \n        _logger.LogInformation(\"Handled {RequestType}\", typeof(TRequest).Name);\n        \n        return response;\n    }\n}\n```\n\n**4. Register Services**\n\n```csharp\n// Register Mediator services\nservices.AddMediator();\n\n// Register handlers\nservices.AddTransient\u003cIRequestHandler\u003cPing, Pong\u003e, PingHandler\u003e();\n\n// Register pipeline behaviors (optional)\nservices.AddTransient(typeof(IPipelineBehavior\u003c,\u003e), typeof(LoggingBehavior\u003c,\u003e));\n```\n\n**5. Use in Controllers**\n\n```csharp\n[ApiController]\n[Route(\"api/[controller]\")]\npublic class PingController : ControllerBase\n{\n    private readonly IMediator _mediator;\n\n    public PingController(IMediator mediator) =\u003e _mediator = mediator;\n\n    [HttpGet]\n    public async Task\u003cActionResult\u003cPong\u003e\u003e Get(\n        [FromQuery] string? message = null,\n        CancellationToken cancellationToken = default)\n    {\n        var request = new Ping { Message = message ?? \"Hello\" };\n        var response = await _mediator.Send(request, cancellationToken);\n        \n        return Ok(response);\n    }\n}\n```\n\n**5. OpenTelemetry Integration (Optional)**\n\nThe mediator provides built-in support for OpenTelemetry tracing and metrics:\n\n```csharp\nusing Arbiter.Mediation;\n\nservices.AddOpenTelemetry()\n    .WithTracing(tracing =\u003e tracing\n        .AddSource(MediatorTelemetry.SourceName)\n        .AddAspNetCoreInstrumentation()\n        .AddConsoleExporter()\n    )\n    .WithMetrics(metrics =\u003e metrics\n        .AddMeter(MediatorTelemetry.MeterName)\n        .AddAspNetCoreInstrumentation()\n        .AddConsoleExporter()\n    );\n```\n\n### Arbiter.CommandQuery\n\nA comprehensive Command Query Responsibility Segregation (CQRS) framework built on top of the mediator pattern.\n\n#### CommandQuery Features\n\n- **CQRS Implementation**: Clear separation between commands and queries\n- **Pre-built Operations**: Common CRUD operations out of the box\n- **Generic Handlers**: Reusable handlers for typical data operations\n- **Smart Behaviors**: Hybrid caching, auditing, validation, and soft delete support\n- **Source-Generated Mapping**: Compile-time object mapping via `Arbiter.Mapping` with `[GenerateMapper]` attribute\n- **Enhanced Querying**: Powerful filter, sort, and pagination support with type-safe operators\n- **Multi-tenancy Ready**: Built-in tenant isolation support\n- **Unified Query System**: Single `EntityQuery` class handles both paged and non-paged scenarios\n- **Flexible Filtering**: Support for complex filter expressions with multiple operators and logic combinations\n\n#### Package Installation\n\n```bash\ndotnet add package Arbiter.CommandQuery\n```\n\n#### Service Registration\n\n```csharp\nservices.AddCommandQuery();\n```\n\n#### Built-in Commands and Queries\n\nThe library provides several pre-built commands and queries for common operations:\n\n**Entity Queries:**\n\n- `EntityIdentifierQuery\u003cTKey, TReadModel\u003e` - Get entity by ID\n- `EntityIdentifiersQuery\u003cTKey, TReadModel\u003e` - Get multiple entities by IDs\n- `EntityPagedQuery\u003cTReadModel\u003e` - Queries both paged and non-paged scenarios with filtering and sorting\n\n**Entity Commands:**\n\n- `EntityCreateCommand\u003cTKey, TCreateModel, TReadModel\u003e` - Create new entities\n- `EntityUpdateCommand\u003cTKey, TUpdateModel, TReadModel\u003e` - Update existing entities (includes upsert)\n- `EntityPatchCommand\u003cTKey, TReadModel\u003e` - Partial updates to entities\n- `EntityDeleteCommand\u003cTKey, TReadModel\u003e` - Delete entities\n\n#### Example Usage\n\n**Query by ID:**\n\n```csharp\nvar query = new EntityIdentifierQuery\u003cint, ProductReadModel\u003e(principal, 123);\nvar result = await mediator.Send(query);\n```\n\n**Query with Filtering and Sorting:**\n\n```csharp\nvar filters = new List\u003cEntityFilter\u003e\n{\n    new EntityFilter { Name = \"Status\", Operator = FilterOperators.Equal, Value = \"Active\" },\n    new EntityFilter { Name = \"Price\", Operator = FilterOperators.GreaterThan, Value = 10.00m }\n};\n\nvar sorts = new List\u003cEntitySort\u003e\n{\n    new EntitySort { Name = \"Name\", Direction = SortDirections.Ascending }\n};\n\nvar query = new EntityQuery\n{\n    Filter = new EntityFilter { Filters = filters },\n    Sort = sorts\n};\n\n// no page or page size will return all matches\nvar command = new EntityPagedQuery\u003cProductReadModel\u003e(principal, query);\nvar result = await mediator.Send(command);\n```\n\n**Paginated Query:**\n\n```csharp\nvar entityQuery = new EntityQuery\n{\n    Filter = new EntityFilter \n    { \n        Name = \"Category\", \n        Operator = FilterOperators.Equal, \n        Value = \"Electronics\" \n    },\n    Sort = new List\u003cEntitySort\u003e\n    {\n        new EntitySort \n        { \n            Name = \"CreatedDate\", \n            Direction = SortDirections.Descending \n        }\n    },\n    Page = 1,\n    PageSize = 20\n};\n\nvar query = new EntityPagedQuery\u003cProductReadModel\u003e(principal, entityQuery);\nvar result = await mediator.Send(query);\n```\n\n**Update Command:**\n\n```csharp\nvar updateModel = new ProductUpdateModel\n{\n    Name = \"Updated Product\",\n    Description = \"Updated description\",\n    Price = 29.99m\n};\n\nvar command = new EntityUpdateCommand\u003cint, ProductUpdateModel, ProductReadModel\u003e(principal, 123, updateModel);\nvar result = await mediator.Send(command);\n```\n\n#### Advanced Filtering and Querying\n\n**Complex Filter Logic:**\n\n```csharp\nvar complexEntityQuery = new EntityQuery\n{\n    Filter = new EntityFilter\n    {\n        Filters = new List\u003cEntityFilter\u003e\n        {\n            new EntityFilter \n            { \n                Name = \"Category\", \n                Operator = FilterOperators.In, \n                Value = new[] { \"Electronics\", \"Computers\" } \n            },\n            new EntityFilter \n            { \n                Name = \"Price\", \n                Operator = FilterOperators.GreaterThanOrEqual, \n                Value = 100.00m \n            },\n            new EntityFilter \n            { \n                Name = \"Name\", \n                Operator = FilterOperators.Contains, \n                Value = \"Gaming\" \n            }\n        },\n        Logic = FilterLogic.And\n    },\n    Sort = new List\u003cEntitySort\u003e\n    {\n        new EntitySort { Name = \"Price\", Direction = SortDirections.Descending },\n        new EntitySort { Name = \"Name\", Direction = SortDirections.Ascending }\n    }\n};\n\nvar query = new EntityPagedQuery\u003cProductReadModel\u003e(principal, complexEntityQuery);\nvar result = await mediator.Send(query);\n```\n\n### Arbiter.Mapping\n\nSource-generated, compile-time object mapping with support for custom property expressions and `IQueryable` projection.\n\n#### Mapping Installation\n\n```bash\ndotnet add package Arbiter.Mapping\n```\n\n#### Mapping Features\n\n- **Source-Generated**: Roslyn incremental source generator emits mapping code at build time\n- **Zero Reflection**: No runtime reflection or expression compilation\n- **AOT Compatible**: Fully compatible with Native AOT\n- **Auto Property Matching**: Automatically maps properties with matching names and compatible types\n- **Custom Expressions**: Configure custom property mappings via `ConfigureMapping`\n- **Query Projection**: Built-in `ProjectTo` support for Entity Framework and other query providers\n- **Record Support**: Supports mapping to records, `init` properties, and primary constructors\n\n#### Basic Usage\n\n**1. Define a Mapper**\n\n```csharp\n[GenerateMapper]\npublic partial class UserToUserDtoMapper : MapperProfile\u003cUser, UserDto\u003e\n{\n    protected override void ConfigureMapping(MappingBuilder\u003cUser, UserDto\u003e mapping)\n    {\n        mapping.Property(d =\u003e d.FullName).From(s =\u003e s.FirstName + \" \" + s.LastName);\n        mapping.Property(d =\u003e d.Age).From(s =\u003e DateTime.Now.Year - s.BirthDate.Year);\n        mapping.Property(d =\u003e d.DepartmentName).From(s =\u003e s.Department!.Name);\n        mapping.Property(d =\u003e d.AddressCount).From(s =\u003e s.Addresses.Count());\n    }\n}\n```\n\n**2. Register the Mapper**\n\n```csharp\nservices.AddSingleton\u003cIMapper\u003cUser, UserDto\u003e, UserToUserDtoMapper\u003e();\nservices.AddSingleton\u003cIMapper, ServiceProviderMapper\u003e();\n```\n\n**3. Use the Mapper**\n\n```csharp\npublic class UserService\n{\n    private readonly IMapper\u003cUser, UserDto\u003e _userMapper;\n\n    public UserService(IMapper\u003cUser, UserDto\u003e userMapper) =\u003e _userMapper = userMapper;\n\n    public UserDto GetUserDto(User user) =\u003e _userMapper.Map(user);\n}\n```\n\n### Arbiter.Services\n\nUtility library providing common infrastructure services for .NET applications.\n\n#### Services Installation\n\n```bash\ndotnet add package Arbiter.Services\n```\n\n#### Services Features\n\n- **CSV Parsing**: Read and write CSV data with flexible configuration\n- **Encryption**: Symmetric encryption and hashing utilities\n- **Caching**: Helpers for building cache keys and managing cache entries\n- **Token Management**: Secure token generation and validation\n- **URL Building**: Fluent API for constructing URLs with query parameters\n\n## Data Providers\n\n### Arbiter.CommandQuery.EntityFramework\n\nEntity Framework Core integration providing ready-to-use handlers for all base commands and queries.\n\n#### CommandQuery EntityFramework Installation\n\n```bash\ndotnet add package Arbiter.CommandQuery.EntityFramework\n```\n\n#### CommandQuery EntityFramework Features\n\n- **Complete CRUD Operations**: Pre-built handlers for all entity operations\n- **Change Tracking**: Automatic audit fields and soft delete support  \n- **Optimized Queries**: Efficient EF Core query patterns\n- **Transaction Support**: Proper transaction management\n- **Bulk Operations**: Support for bulk insert/update operations\n\n#### Setup\n\n```csharp\n// Add Entity Framework Core services\nservices.AddDbContext\u003cTrackerContext\u003e(options =\u003e\n    options.UseSqlServer(connectionString)\n);\n\n// Register Command Query services\nservices.AddCommandQuery();\n\n// Register source-generated mappers\nservices.AddSingleton\u003cIMapper\u003cProduct, ProductReadModel\u003e, ProductToReadModelMapper\u003e();\nservices.AddSingleton\u003cIMapper\u003cProductCreateModel, Product\u003e, ProductCreateModelToProductMapper\u003e();\nservices.AddSingleton\u003cIMapper\u003cProductUpdateModel, Product\u003e, ProductUpdateModelToProductMapper\u003e();\nservices.AddSingleton\u003cIMapper, ServiceProviderMapper\u003e();\n\n// Register Entity Framework handlers for each entity\nservices.AddEntityQueries\u003cTrackerContext, Product, int, ProductReadModel\u003e();\nservices.AddEntityCommands\u003cTrackerContext, Product, int, ProductReadModel, ProductCreateModel, ProductUpdateModel\u003e();\n```\n\n### Arbiter.CommandQuery.MongoDB\n\nMongoDB integration providing handlers for all base commands and queries with document database optimizations.\n\n```bash\ndotnet add package Arbiter.CommandQuery.MongoDB\n```\n\n#### MongoDB Setup\n\n```csharp\n// Add MongoDB Repository services\nservices.AddMongoRepository(\"Tracker\");\nservices.AddCommandQuery();\n\n// Register source-generated mappers\nservices.AddSingleton\u003cIMapper\u003cProduct, ProductReadModel\u003e, ProductToReadModelMapper\u003e();\nservices.AddSingleton\u003cIMapper\u003cProductCreateModel, Product\u003e, ProductCreateModelToProductMapper\u003e();\nservices.AddSingleton\u003cIMapper\u003cProductUpdateModel, Product\u003e, ProductUpdateModelToProductMapper\u003e();\nservices.AddSingleton\u003cIMapper, ServiceProviderMapper\u003e();\n\n// Register MongoDB handlers for each entity\nservices.AddEntityQueries\u003cIMongoEntityRepository\u003cProduct\u003e, Product, string, ProductReadModel\u003e();\nservices.AddEntityCommands\u003cIMongoEntityRepository\u003cProduct\u003e, Product, string, ProductReadModel, ProductCreateModel, ProductUpdateModel\u003e();\n```\n\n## Web Integration\n\n### Arbiter.CommandQuery.Endpoints\n\nMinimal API endpoints that automatically expose your commands and queries as REST APIs.\n\n```bash\ndotnet add package Arbiter.CommandQuery.Endpoints\n```\n\n#### Endpoints Setup\n\n```csharp\nvar builder = WebApplication.CreateBuilder(args);\n\n// Add endpoint services\nbuilder.Services.AddEndpointRoutes();\n\nvar app = builder.Build();\n\n// Map endpoint routes\napp.MapEndpointRoutes();\n\napp.Run();\n```\n\n**Custom Endpoint:**\n\n```csharp\npublic class ProductEndpoint : EntityCommandEndpointBase\u003cint, ProductReadModel, ProductReadModel, ProductCreateModel, ProductUpdateModel\u003e\n{\n    public ProductEndpoint(ILoggerFactory loggerFactory)\n        : base(loggerFactory, \"Product\")\n    {\n    }\n}\n\n// Register the endpoint\nbuilder.Services.AddSingleton\u003cIEndpointRoute, ProductEndpoint\u003e();\n```\n\n### Arbiter.CommandQuery.Mvc\n\nMVC Controllers for base Commands and Queries with full ASP.NET Core integration.\n\n```bash\ndotnet add package Arbiter.CommandQuery.Mvc\n```\n\n## Blazor Dispatcher\n\nThe Dispatcher libraries provide a unified `IDispatcher` abstraction for sending commands and queries from Blazor components, with full support for **Blazor Auto render mode**. Components depend only on `IDispatcher`; the correct transport is wired at startup based on the render environment.\n\n| Render mode        | Implementation                             | Transport                            |\n| :----------------- | :----------------------------------------- | :----------------------------------- |\n| WebAssembly        | `MessagePackDispatcher` / `JsonDispatcher` | HTTP POST to `/api/dispatcher/send`  |\n| Server Interactive | `ServerDispatcher`                         | Direct `IMediator` call (in-process) |\n\n### Arbiter.Dispatcher.Server\n\nProvides the `DispatcherEndpoint`—a single `POST /api/dispatcher/send` HTTP endpoint that deserializes incoming requests (JSON or MessagePack), resolves the target handler via `IMediator`, and streams the response back to the WASM client.\n\n```bash\ndotnet add package Arbiter.Dispatcher.Server\n```\n\n#### Server Setup\n\n```csharp\n// Program.cs — Blazor host project\nbuilder.Services.AddDispatcherService();\n\n// ...\n\napp.MapDispatcherService().RequireAuthorization();\n```\n\n### Arbiter.Dispatcher.Client\n\nProvides `IDispatcher` and its implementations, plus `DispatcherDataService`, `ModelStateManager\u003cTModel\u003e`, `ModelStateLoader\u003cTKey, TModel\u003e`, and `ModelStateEditor\u003cTKey, TReadModel, TUpdateModel\u003e` for Blazor component state management.\n\n```bash\ndotnet add package Arbiter.Dispatcher.Client\n```\n\n#### Client Setup — WebAssembly\n\n```csharp\n// Program.cs — WASM client project\nbuilder.Services\n    .AddMessagePackDispatcher((sp, client) =\u003e\n    {\n        client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);\n    });\n```\n\n#### Client Setup — Server Interactive\n\n```csharp\n// Program.cs — Blazor host project\nbuilder.Services.AddServerDispatcher();\n```\n\n#### Client Setup — Blazor Auto render mode\n\nRegister both dispatchers so each render environment resolves `IDispatcher` correctly:\n\n```csharp\n// Host project: server-side rendering + serves WASM clients\nbuilder.Services.AddServerDispatcher();\nbuilder.Services.AddDispatcherService();\n\n// WASM client project: WebAssembly rendering\nbuilder.Services\n    .AddMessagePackDispatcher((sp, client) =\u003e\n    {\n        client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);\n    });\n```\n\n#### Sending commands and queries\n\nInject `IDispatcher` or the higher-level `IDispatcherDataService` into any component or service:\n\n```csharp\n// Low-level: IDispatcher\nvar query = new EntityIdentifierQuery\u003cint, UserReadModel\u003e(principal, userId);\nvar user = await dispatcher.Send\u003cEntityIdentifierQuery\u003cint, UserReadModel\u003e, UserReadModel\u003e(\n    query, cancellationToken);\n\n// High-level: IDispatcherDataService\nvar user = await dataService.Get\u003cint, UserReadModel\u003e(userId);\nvar page = await dataService.Page\u003cUserReadModel\u003e(entityQuery);\nvar saved = await dataService.Save\u003cint, UserUpdateModel, UserReadModel\u003e(userId, updateModel);\n```\n\n#### Component state management\n\n`ModelStateEditor` manages the full load–edit–save–delete lifecycle for a Blazor edit form:\n\n```csharp\n@inject ModelStateEditor\u003cint, UserReadModel, UserUpdateModel\u003e Store\n@implements IDisposable\n\nprotected override async Task OnInitializedAsync()\n{\n    Store.OnStateChanged += (_, _) =\u003e InvokeAsync(StateHasChanged);\n\n    if (IsCreate)\n        Store.New();\n    else\n        await Store.Load(Id);\n}\n\n// Store.IsBusy  — true while a load/save/delete is in progress\n// Store.IsDirty — true when the model has unsaved changes\n// Store.Model   — the editable update model bound to the form\n// Store.Save()  / Store.Delete() / Store.Cancel()\n\npublic void Dispose() =\u003e Store.OnStateChanged -= HandleStateChanged;\n```\n\n## Communication\n\n### Arbiter.Communication\n\nA flexible message templating system for email and SMS communications with support for multiple providers.\n\n```bash\ndotnet add package Arbiter.Communication\n```\n\n#### Communication Providers\n\n**Azure Communication Services:**\n\n```bash\ndotnet add package Arbiter.Communication.Azure\n```\n\n**SendGrid and Twilio:**\n\n```bash\ndotnet add package Arbiter.Communication.Twilio\n```\n\n## Documentation\n\n- **[Complete Documentation](https://loresoft.github.io/Arbiter/)** - Comprehensive guides and API reference\n- **[Quick Start Guide](https://loresoft.github.io/Arbiter/guide/quickStart.html)** - Get up and running quickly\n- **[Architecture Patterns](https://loresoft.github.io/Arbiter/guide/patterns.html)** - Best practices and patterns\n- **[Blazor Dispatcher Overview](https://loresoft.github.io/Arbiter/guide/dispatcher/overview.html)** - Dispatcher architecture, WASM and Server Interactive setup\n- **[Dispatcher Server](https://loresoft.github.io/Arbiter/guide/dispatcher/server.html)** - Server endpoint configuration, security, and diagnostics\n- **[Dispatcher Client](https://loresoft.github.io/Arbiter/guide/dispatcher/client.html)** - Client registration, sending commands and queries\n- **[State Management](https://loresoft.github.io/Arbiter/guide/dispatcher/state.html)** - ModelStateManager, ModelStateLoader, ModelStateEditor\n\n## Samples\n\nExplore practical examples in the [samples](./samples/) directory:\n\n- **[Entity Framework Sample](./samples/EntityFramework/)** - Complete CRUD operations with EF Core\n- **[MongoDB Sample](./samples/MongoDB/)** - Document database implementation\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.\n\n1. Fork the repository\n2. Create your feature branch (git checkout -b feature/amazing-feature)\n3. Commit your changes (git commit -m 'Add amazing feature')\n4. Push to the branch (git push origin feature/amazing-feature)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE) - see the LICENSE file for details.\n\n## Support\n\nIf you find this project useful, please consider:\n\n- **Starring** the repository\n- **Reporting** issues\n- **Contributing** improvements\n- **Spreading** the word\n\n## Change Log\n\n### Version 2.0\n\n#### Major Breaking Changes and Improvements\n\n##### Breaking Changes\n\n- **Removed `EntitySelectQuery`**: Replaced with enhanced `EntityQuery` that now supports both paged and non-paged results\n- **Removed `EntityUpsertCommand`**: Upsert functionality has been unified into `EntityUpdateCommand` with built-in upsert logic\n- **Removed `EntityContinuationQuery` and `EntityContinuationResult`**: Functionality now integrated into `EntityQuery`\n- **Command/Query Reorganization**:\n  - Moved query classes (`EntityIdentifierQuery`, `EntityIdentifiersQuery`, `EntityPagedQuery`) to `Commands` namespace for better organization\n  - Renamed base classes for consistency:\n    - `EntityIdentifierCommand` → `EntityIdentifierBase`\n    - `EntityIdentifiersCommand` → `EntityIdentifiersBase`\n    - `EntityModelCommand` → `EntityModelBase`\n  - Renamed filter, logic, and sort values for more consistent query building\n    - `EntityFilterOperators` → `FilterOperators`\n    - `EntityFilterLogic` → `FilterLogic`\n    - `EntitySortDirections` → `SortDirections`\n\n##### Architecture Improvements\n\n- **Simplified Query System**:\n  - Consolidated multiple query types into a single, more powerful `EntityQuery` class\n  - Removed redundant query handlers and behaviors\n  - Enhanced filter and sort capabilities with better type safety\n\n- **Enhanced Filtering**:\n  - Moved filter logic to dedicated `Queries.FilterLogic` and `Queries.FilterOperators` enums\n  - Improved `EntityFilterConverter` with better validation and error handling\n  - Enhanced `LinqExpressionBuilder` with more robust query building capabilities\n\n- **Caching Simplification**:\n  - Removed `DistributedCacheQueryBehavior` and `MemoryCacheQueryBehavior`\n  - Consolidated caching logic into `HybridCacheQueryBehavior` for better performance\n  - Removed `IDistributedCacheSerializer` interface in favor of built-in serialization\n\n##### Behavior Consolidation\n\n- **Tenant Behaviors**:\n  - Removed `TenantFilterBehaviorBase` and `TenantSelectQueryBehavior`\n  - Enhanced `TenantPagedQueryBehavior` to handle all tenant-related query filtering\n  \n- **Soft Delete Behaviors**:\n  - Removed `DeletedFilterBehaviorBase` and `DeletedSelectQueryBehavior`\n  - Enhanced `DeletedPagedQueryBehavior` to handle all soft delete scenarios\n\n- **Removed Legacy Behaviors**:\n  - `TrackChangeCommandBehavior` - functionality moved to handlers\n  - Various base behavior classes that were no longer needed\n\n#### Migration from Version 1.x\n\n**Updating Query Usage:**\n\n```csharp\n// Version 1.x - EntitySelectQuery (REMOVED)\nvar oldQuery = new EntitySelectQuery\u003cProductReadModel\u003e(principal, filter, sort);\n\n// Version 2.0 - Use EntityPagedQuery with EntityQuery instead\nvar entityQuery = new EntityQuery\n{\n    Filter = filter,\n    Sort = sorts\n};\nvar newQuery = new EntityPagedQuery\u003cProductReadModel\u003e(principal, entityQuery);\n```\n\n**Updating Filter Operators:**\n\n```csharp\n// Version 1.x - String operators (DEPRECATED)\nvar oldFilter = new EntityFilter \n{ \n    Name = \"Status\", \n    Operator = \"eq\", \n    Value = \"Active\" \n};\n\n// Version 2.0 - Enum operators\nvar newFilter = new EntityFilter \n{ \n    Name = \"Status\", \n    Operator = FilterOperators.Equal, \n    Value = \"Active\" \n};\n```\n\n**Updating Sort Directions:**\n\n```csharp\n// Version 1.x - String directions (DEPRECATED)\nvar oldSort = new EntitySort \n{ \n    Name = \"Name\", \n    Direction = \"asc\" \n};\n\n// Version 2.0 - Enum directions\nvar newSort = new EntitySort \n{ \n    Name = \"Name\", \n    Direction = SortDirections.Ascending \n};\n```\n\n**Upsert Operations:**\n\n```csharp\n// Version 1.x - Separate EntityUpsertCommand (REMOVED)\nvar oldUpsert = new EntityUpsertCommand\u003cint, ProductUpsertModel, ProductReadModel\u003e(principal, model);\n\n// Version 2.0 - Use EntityUpdateCommand with upsert behavior\nvar newUpdate = new EntityUpdateCommand\u003cint, ProductUpdateModel, ProductReadModel\u003e(principal, id, model, true);\n```\n","funding_links":["https://github.com/sponsors/loresoft"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floresoft%2Farbiter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Floresoft%2Farbiter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floresoft%2Farbiter/lists"}