{"id":47699230,"url":"https://github.com/qorpe/mediator","last_synced_at":"2026-04-02T17:02:30.560Z","repository":{"id":347601992,"uuid":"1194081322","full_name":"qorpe/mediator","owner":"qorpe","description":"Enterprise-grade CQRS mediator for .NET — Result pattern, pipeline behaviors, DDD-ready. Free forever.","archived":false,"fork":false,"pushed_at":"2026-03-28T17:49:55.000Z","size":117,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-28T17:55:07.183Z","etag":null,"topics":["behavior","cqrs","csharp","ddd","dotnet","enterprise","mediator","notifications","validations"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qorpe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"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}},"created_at":"2026-03-27T22:39:21.000Z","updated_at":"2026-03-28T17:49:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/qorpe/mediator","commit_stats":null,"previous_names":["qorpe/mediator"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/qorpe/mediator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qorpe%2Fmediator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qorpe%2Fmediator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qorpe%2Fmediator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qorpe%2Fmediator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qorpe","download_url":"https://codeload.github.com/qorpe/mediator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qorpe%2Fmediator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31311017,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["behavior","cqrs","csharp","ddd","dotnet","enterprise","mediator","notifications","validations"],"created_at":"2026-04-02T17:01:42.651Z","updated_at":"2026-04-02T17:02:30.548Z","avatar_url":"https://github.com/qorpe.png","language":"C#","readme":"# Qorpe.Mediator\n\n**Enterprise-Grade CQRS Mediator for .NET**\n\n[![NuGet](https://img.shields.io/nuget/vpre/Qorpe.Mediator.svg)](https://www.nuget.org/packages/Qorpe.Mediator/)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/Qorpe.Mediator.svg)](https://www.nuget.org/packages/Qorpe.Mediator/)\n[![Build](https://github.com/qorpe/mediator/actions/workflows/ci.yml/badge.svg)](https://github.com/qorpe/mediator/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![.NET](https://img.shields.io/badge/.NET-8.0%20%7C%209.0%20%7C%2010.0-blue)](https://dotnet.microsoft.com/)\n\nA production-ready CQRS mediator library for .NET with Result pattern, pipeline behaviors, DDD support, and attribute-based HTTP endpoint mapping.\n\n- - -\n\n## Why Qorpe.Mediator?\n\n- **Result Pattern built-in** — No more throwing exceptions for control flow\n- **Explicit CQRS** — `ICommand\u003cT\u003e`, `IQuery\u003cT\u003e` instead of just `IRequest`\n- **10 built-in behaviors** — Audit, logging, validation, auth, transactions, retry, caching, performance, idempotency, cache invalidation\n- **Attribute-based HTTP endpoints** — `[HttpEndpoint]` eliminates controller boilerplate\n- **DDD native** — `IDomainEvent`, aggregate root patterns\n- **Publish performance** — Up to 66% faster notification fanout with 4.7x less memory ([benchmarks](docs/BENCHMARKS.md))\n- **221 tests** — Unit, integration, load, E2E\n\n- - -\n\n## Performance\n\nBenchmarked against MediatR v12 using BenchmarkDotNet. Full results: [docs/BENCHMARKS.md](docs/BENCHMARKS.md)\n\n### Publish (Notification Fanout) — Qorpe wins\n\n| Handlers | Qorpe | MediatR v12 | Result |\n|----------|-------|-------------|--------|\n| 1 handler | 24 ns / 88 B | 46 ns / 288 B | **48% faster, 3.3x less memory** |\n| 10 handlers | 69 ns / 376 B | 187 ns / 1,656 B | **63% faster, 4.4x less memory** |\n| 100 handlers | 532 ns / 3,256 B | 1,552 ns / 15,336 B | **66% faster, 4.7x less memory** |\n\n### Send (Pipeline) — Equal speed, Qorpe uses less memory\n\n| Behaviors | Qorpe | MediatR v12 | Result |\n|-----------|-------|-------------|--------|\n| 1 behavior | 61 ns / 288 B | 59 ns / 368 B | ~equal speed, **22% less memory** |\n| 3 behaviors | 89 ns / 560 B | 90 ns / 656 B | **Qorpe 1% faster, 15% less memory** |\n| 5 behaviors | 119 ns / 832 B | 118 ns / 944 B | ~equal speed, **12% less memory** |\n\n- - -\n\n## Quick Start\n\n### 1. Install\n\n```bash\ndotnet add package Qorpe.Mediator\n```\n\n### 2. Register\n\n```csharp\nbuilder.Services.AddQorpeMediator(cfg =\u003e\n    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));\n```\n\n### 3. Define a Command\n\n```csharp\npublic record CreateOrderCommand(string UserId, List\u003cOrderItem\u003e Items)\n    : ICommand\u003cResult\u003cGuid\u003e\u003e;\n```\n\n### 4. Handle it\n\n```csharp\npublic class CreateOrderHandler : ICommandHandler\u003cCreateOrderCommand, Result\u003cGuid\u003e\u003e\n{\n    public ValueTask\u003cResult\u003cGuid\u003e\u003e Handle(CreateOrderCommand request, CancellationToken ct)\n    {\n        var orderId = Guid.NewGuid();\n        // ... create order\n        return new ValueTask\u003cResult\u003cGuid\u003e\u003e(Result\u003cGuid\u003e.Success(orderId));\n    }\n}\n```\n\n### 5. Send\n\n```csharp\nvar result = await mediator.Send(new CreateOrderCommand(\"user-1\", items));\nresult.Match(\n    id =\u003e Console.WriteLine($\"Order created: {id}\"),\n    error =\u003e Console.WriteLine($\"Failed: {error}\")\n);\n```\n\n- - -\n\n## Features\n\n### CQRS Separation\n\n```csharp\n// Commands — change state\npublic record CreateOrder(string UserId) : ICommand\u003cResult\u003cGuid\u003e\u003e;\npublic record CancelOrder(Guid Id) : ICommand\u003cResult\u003e;\n\n// Queries — read state, no side effects\npublic record GetOrderById(Guid Id) : IQuery\u003cResult\u003cOrder\u003e\u003e;\n\n// Streaming\npublic record SearchOrders(string? Status) : IStreamRequest\u003cOrder\u003e;\n```\n\n### Result Pattern\n\n```csharp\n// Success\nreturn Result\u003cGuid\u003e.Success(orderId);\n\n// Failure with typed errors\nreturn Error.NotFound(\"Order.NotFound\", \"Order not found\");\n\n// Functional operations\nvar name = result.Map(order =\u003e order.Name)\n                 .Bind(name =\u003e ValidateName(name))\n                 .Match(\n                     name =\u003e $\"Hello, {name}\",\n                     error =\u003e $\"Error: {error.Description}\");\n```\n\n### Domain Events\n\n```csharp\npublic record OrderCreatedEvent(Guid OrderId, string UserId) : IDomainEvent\n{\n    public DateTimeOffset OccurredOn { get; } = DateTimeOffset.UtcNow;\n}\n\n// Multiple handlers per event\npublic class SendEmail : INotificationHandler\u003cOrderCreatedEvent\u003e { ... }\npublic class UpdateInventory : INotificationHandler\u003cOrderCreatedEvent\u003e { ... }\n\nawait publisher.Publish(new OrderCreatedEvent(orderId, userId));\n```\n\n### HTTP Endpoint Mapping\n\n```csharp\n[HttpEndpoint(\"POST\", \"/api/orders\", Tags = new[] { \"Orders\" })]\n[Transactional]\n[Auditable]\npublic record CreateOrderCommand : ICommand\u003cResult\u003cGuid\u003e\u003e { ... }\n\n// In Program.cs\napp.MapQorpeEndpoints(typeof(Program).Assembly);\n// Result auto-mapped: Success-\u003e200/201, Validation-\u003e400, NotFound-\u003e404, etc.\n```\n\n- - -\n\n## Pipeline Behaviors\n\nAll behaviors are attribute-driven, configurable, and automatically ordered via `IBehaviorOrder`.\n\n| # | Behavior | Attribute | Order | Description |\n|---|----------|-----------|-------|-------------|\n| 1 | **Audit** | `[Auditable]` | 100 | Async batching, store abstraction, sensitive data masking |\n| 2 | **Logging** | Auto | 200 | Structured logging, auto-mask, circular reference safe |\n| 3 | **UnhandledException** | Auto | 300 | Catch-all safety net, always re-throws |\n| 4 | **Authorization** | `[Authorize]` | 400 | Role + policy checking, Result-based responses |\n| 5 | **Validation** | Auto | 500 | FluentValidation multi-validator, Result.Failure |\n| 6 | **Idempotency** | `[Idempotent]` | 600 | SHA256 key, per-key locking, window-based expiry |\n| 7 | **Transaction** | `[Transactional]` | 700 | Command-only, rollback, distinct commit/handler errors |\n| 8 | **Performance** | `[PerformanceThreshold]` | 800 | Per-request thresholds, 30s hard ceiling |\n| 9 | **Retry** | `[Retryable]` | 900 | Exponential backoff with jitter, success attempt logging |\n| 10 | **Caching** | `[Cacheable]` | 1000 | Query-only, bounded lock pool, stampede prevention |\n| 11 | **Cache Invalidation** | `[InvalidatesCache]` | 1001 | Command-driven cache invalidation by key prefix |\n\n### Full Configuration\n\n```csharp\nbuilder.Services.AddQorpeMediator(cfg =\u003e\n{\n    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);\n    cfg.NotificationPublishStrategy = NotificationPublishStrategy.Parallel;\n    cfg.EnablePolymorphicNotifications = true;\n    cfg.ValidateOnStartup = true;\n});\n\nbuilder.Services.AddQorpeValidation(typeof(Program).Assembly);\n\nbuilder.Services.AddQorpeAllBehaviors(opts =\u003e\n{\n    opts.ConfigureLogging = log =\u003e\n    {\n        log.MaskProperties.Add(\"CardNumber\");\n        log.MaxSerializedLength = 4096;\n    };\n    opts.ConfigurePerformance = perf =\u003e\n    {\n        perf.WarningThresholdMs = 500;\n        perf.CriticalThresholdMs = 5000;\n    };\n});\n```\n\n- - -\n\n## MediatR vs Qorpe.Mediator\n\n| Feature | MediatR v12 | Qorpe.Mediator |\n|---------|-------------|----------------|\n| License | Commercial (2025+) | **MIT** |\n| Publish Performance | Baseline | **Up to 66% faster** |\n| Publish Memory | Baseline | **Up to 4.7x less** |\n| Result Pattern | No (exceptions) | **Built-in Result\\\u003cT\\\u003e** |\n| CQRS Types | IRequest only | **ICommand, IQuery, IRequest** |\n| Domain Events | INotification | **IDomainEvent + INotification** |\n| Pre/Post Processors | Defined, wired | **Defined, wired** |\n| Behavior Ordering | Registration order | **Explicit IBehaviorOrder** |\n| Polymorphic Notifications | No | **Opt-in** |\n| Startup Validation | No | **ValidateOnStartup** |\n| Built-in Behaviors | 0 | **11** |\n| HTTP Endpoints | No | **[HttpEndpoint] attribute** |\n| Cache Invalidation | No | **[InvalidatesCache] attribute** |\n| ValueTask | No (Task) | **Yes (ValueTask)** |\n| Cancellation Diagnostics | No | **Pipeline stage tracking** |\n| Stream Pipeline Behaviors | No | **IStreamPipelineBehavior** |\n| Sensitive Data | No | **[SensitiveData] auto-mask** |\n| Telemetry | Yes | **None** |\n\n- - -\n\n## Test Coverage\n\n| Layer | Tests | What It Covers |\n|-------|-------|----------------|\n| **Unit** | 182 | Result, Error, Guard, Mediator, all behaviors, notifications, validation, pre/post processors |\n| **Integration** | 21 | Full pipeline E2E, HTTP endpoints, cross-behavior, DI registration |\n| **Load** | 18 | 50K concurrent, 500K sequential, memory stability, streaming, latency percentiles |\n| **Total** | **221** | Production-grade coverage |\n\n- - -\n\n## Packages\n\n| Package | Description |\n|---------|-------------|\n| `Qorpe.Mediator` | Core — CQRS abstractions, Result pattern, Mediator implementation |\n| `Qorpe.Mediator.Behaviors` | 11 built-in pipeline behaviors |\n| `Qorpe.Mediator.FluentValidation` | FluentValidation integration — auto-discovery, multi-validator |\n| `Qorpe.Mediator.AspNetCore` | HTTP endpoint mapping — [HttpEndpoint], Result-to-HTTP, OpenAPI |\n| `Qorpe.Mediator.Contracts` | Shared contracts for multi-project solutions |\n\n- - -\n\n## Sample Project\n\nSee [`tests/Qorpe.Mediator.Sample.ECommerce/`](tests/Qorpe.Mediator.Sample.ECommerce/) for a complete e-commerce example with:\n- Order aggregate root with domain events\n- Commands with transactions, audit, authorization, idempotency, and retry\n- Queries with caching and streaming\n- FluentValidation validators\n- Attribute-based HTTP endpoint mapping\n- Full behavior pipeline configuration\n\n- - -\n\n## Migration from MediatR\n\nSee [docs/MIGRATION_GUIDE.md](docs/MIGRATION_GUIDE.md) for a step-by-step migration guide.\n\n- - -\n\n## Contributing\n\nContributions are welcome! Please open an issue or submit a pull request.\n\n- - -\n\n## License\n\n[MIT License](LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqorpe%2Fmediator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqorpe%2Fmediator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqorpe%2Fmediator/lists"}