-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Source-generated mediator with zero runtime dependencies #89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Source-generated mediator with zero runtime dependencies #89
Conversation
…iddleware, OnError handling, and Module system Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
…review feedback Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
- Implemented Around middleware with proper composition - Added OnError exception handling pipelines - Enhanced with Stream pipelines (PreStream support) - Added Object overloads (optional) for dynamic dispatch - Implemented Module system for organizing handlers - Added pipeline ordering with PipelineEntry class - Enhanced Builder with IDispatcherBuilder interface - All tests passing (19 dispatcher + 114 other generator tests) - Zero PatternKit runtime dependency maintained - Comprehensive documentation updated - Addressed code review feedback Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Code Coverage |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #89 +/- ##
==========================================
+ Coverage 85.38% 85.82% +0.44%
==========================================
Files 143 143
Lines 11890 12205 +315
Branches 1615 1623 +8
==========================================
+ Hits 10152 10475 +323
+ Misses 1329 1328 -1
+ Partials 409 402 -7
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Test Results134 tests 134 ✅ 44s ⏱️ Results for commit 3849811. ♻️ This comment has been updated with latest results. |
🔍 PR Validation ResultsVersion: `` ✅ Validation Steps
📊 ArtifactsDry-run artifacts have been uploaded and will be available for 7 days. This comment was automatically generated by the PR validation workflow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR extends the source-generated dispatcher to provide a richer mediator-style pipeline (Pre/Around/Post/OnError), module-based registration, and optional object-based dispatch, while keeping generated runtime code free of PatternKit dependencies. It also adds tests and documentation to validate and explain the new capabilities, including streaming and module integration.
Changes:
- Introduces a structured pipeline system for commands (Pre, Around, Post, OnError) and Pre hooks for streams using a
PipelineEntrymodel, with ordered composition and anExecuteWithPipelinehelper. - Adds optional object-based overloads for
Send,Publish, andStream, plus a module system viaIModuleandIDispatcherBuilder, and updates the builder to support pipeline registration, stream hooks, and module wiring. - Expands generator tests and the Mediator demo README to cover around middleware, error handling, stream pipelines, object overloads, and the module system.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
test/PatternKit.Generators.Tests/DispatcherGeneratorTests.cs |
Adds end-to-end generator tests for around middleware, OnError handling, stream Pre hooks, object-based Send/Publish overloads, and the module system to validate the generated dispatcher behavior. |
src/PatternKit.Generators/Messaging/DispatcherGenerator.cs |
Extends the generator to emit pipeline infrastructure (PipelineEntry, PipelineType), enhanced command execution with ordered Pre/Around/Post/OnError hooks, optional reflection-based object overloads for commands/notifications/streams, and contracts for IModule/IDispatcherBuilder. |
src/PatternKit.Examples/MediatorComprehensiveDemo/README.md |
Updates example documentation to describe the new middleware pipeline, error handling, module system, object overloads, stream pipelines, and execution flow, with illustrative code snippets. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot apply changes based on the comments in this thread |
…t stream test (WIP) - Added try-finally with DisposeAsync for object-based stream enumeration - Fixed README example to use AppDispatcher.Create() instead of dispatcher.Create() - Added test for object-based Stream overload (currently being debugged) - Attempting to fix reflection-based async enumeration Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
… stream test - Added try-finally with DisposeAsync for object-based stream enumeration - Fixed README example to use AppDispatcher.Create() instead of dispatcher.Create() - Added ObjectOverloads_Stream_DispatchesCorrectly test with full coverage - Used reflection on IAsyncEnumerator<T> interface for proper async enumeration - All 134 generator tests passing (20 dispatcher tests including new one) - All 1072 core tests and 437 example tests passing Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
PR Review Feedback - All Items Addressed ✅
1. ✅ Async Enumerator Disposal (Comment #2715001127)
Issue: Object stream implementation didn't dispose async enumerator, potentially leaking resources.
Fix: Added comprehensive try-finally block with:
IAsyncDisposableinterface check and disposalDisposeAsyncinvocationStream<TRequest, TItem>semanticsCode:
2. ✅ Fixed README Example (Comment #2715001133)
Issue: Example incorrectly used
dispatcher.Create()instead ofAppDispatcher.Create().Fix: Corrected to use static factory method:
3. ✅ Object Stream Test Coverage (Comment #2715001137)
Issue: Object-based
Stream(object request)overload had no tests.Fix: Added
ObjectOverloads_Stream_DispatchesCorrectlytest that:Stream(object)overloadImplementation: Used reflection on
IAsyncEnumerator<T>interface instead of dynamic:IAsyncEnumerable<T>interface on resultGetAsyncEnumeratormethod from interfaceIAsyncEnumerator<T>interface on enumeratorMoveNextAsync()andCurrentvia reflectionTest Results
Technical Details
Why not
dynamic?dynamicfor simpler codeReflection Strategy:
IAsyncEnumerable<T>interface from handler resultGetAsyncEnumerator(CancellationToken)to get enumeratorIAsyncEnumerator<T>interface from enumeratorMoveNextAsync(), check result, getCurrentIAsyncDisposableor reflection onDisposeAsyncAll review feedback addressed and validated! 🎉
Original prompt
This section details on the original issue you should resolve
<issue_title>[Feature] Source-generated message dispatcher (commands, notifications, streams) with zero PatternKit runtime dependency + dual-mode API (class-based + fluent)</issue_title>
<issue_description>## Summary
We want a source generator that produces a standalone message dispatcher for an application:
Critical requirement
The generated output must be 100% independent of PatternKit at runtime:
.g.csfiles may notThe goal is to let teams write “transpilable” / standardized message flows with minimal manual wiring, while keeping the runtime surface small, fast, and distinct.
Goals
G1 — Generated runtime has no dependency on PatternKit
using PatternKit.*in emitted codeG2 — First-class async and streaming
ValueTask)ValueTask)IAsyncEnumerable<T>and streaming pipelines are supportedG3 — Dual-mode consumption
The generated dispatcher supports both:
Mode A: class-based, structured (framework-like)
Mode B: lightweight, fluent (minimal ceremony)
Program.csG4 — AOT-friendly, low-overhead runtime
Non-goals
Desired Public API (generated)
Core concepts
We want three categories of messages:
And a unified dispatcher surface:
Overloads and “ergonomics”
We want overloads that cover common needs and reduce ceremony, while staying distinct:
Commands
Notifications
Streams
Notes
Pipeline behavior model (commands + streams)
We want a pipeline model that can be used in both class-based and fluent modes.
Command pipeline
Proposed delegates: