Skip to content

Commit 6141e39

Browse files
committed
Fix build warning
1 parent 8ad3462 commit 6141e39

9 files changed

+104
-6
lines changed

docs/guide/endpoints.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,74 @@ Handlers for event/notification types are automatically excluded from endpoint g
666666
The `INotification` interface is **not required** for events to be excluded from endpoints or for cascading/publishing to work. Events are excluded based on naming conventions (suffixes like `Created`, `Deleted`, etc.) regardless of interface implementation. `INotification` is a classification tool — use it when you want a handler that can receive all notification-type messages, or simply as self-documentation.
667667
:::
668668

669+
## Streaming Handlers
670+
671+
Foundatio Mediator supports handlers that return `IAsyncEnumerable<T>` for streaming data incrementally — useful for large datasets, real-time feeds, or progressive processing. These work through both the mediator and generated endpoints:
672+
673+
```csharp
674+
public class ProductStreamHandler
675+
{
676+
public async IAsyncEnumerable<Product> HandleAsync(
677+
GetProductStream query,
678+
IProductRepository repository,
679+
[EnumeratorCancellation] CancellationToken cancellationToken = default)
680+
{
681+
await foreach (var product in repository.GetProductsAsync(
682+
query.CategoryId, cancellationToken))
683+
{
684+
yield return product;
685+
}
686+
}
687+
}
688+
```
689+
690+
Consume streaming results through the mediator:
691+
692+
```csharp
693+
await foreach (var product in mediator.InvokeStreamAsync<Product>(
694+
new GetProductStream("electronics"), cancellationToken))
695+
{
696+
Console.WriteLine(product.Name);
697+
}
698+
```
699+
700+
When endpoint generation is enabled, streaming handlers automatically generate HTTP endpoints that return the `IAsyncEnumerable<T>` directly — ASP.NET Core streams items as a JSON array without buffering.
701+
702+
### Server-Sent Events (SSE)
703+
704+
For real-time push scenarios, set `Streaming = EndpointStreaming.ServerSentEvents` on the endpoint to use Server-Sent Events instead of JSON array streaming:
705+
706+
```csharp
707+
[Handler]
708+
public class EventStreamHandler(IMediator mediator)
709+
{
710+
[HandlerEndpoint(
711+
Route = "/events/stream",
712+
Streaming = EndpointStreaming.ServerSentEvents,
713+
SseEventType = "event",
714+
Summary = "Subscribe to real-time events via SSE")]
715+
public async IAsyncEnumerable<ClientEvent> Handle(
716+
SubscribeToEvents message,
717+
[EnumeratorCancellation] CancellationToken cancellationToken)
718+
{
719+
await foreach (var evt in mediator.SubscribeAsync<IDispatchToClient>(
720+
cancellationToken: cancellationToken))
721+
{
722+
yield return new ClientEvent(evt.GetType().Name, evt);
723+
}
724+
}
725+
}
726+
```
727+
728+
| Property | Purpose |
729+
| --- | --- |
730+
| `Streaming` | `EndpointStreaming.ServerSentEvents` wraps the result with `TypedResults.ServerSentEvents()` (requires .NET 10+). `Default` streams as a JSON array. |
731+
| `SseEventType` | Sets the `event:` field in the SSE stream. When set, clients listen with `addEventListener('event-name', ...)`. When `null`, the browser `EventSource` fires the default `message` event. |
732+
733+
::: tip
734+
For a complete guide on streaming patterns including `SubscribeAsync`, error handling, and real-world examples, see [Streaming Handlers](./streaming-handlers.md#streaming-endpoints).
735+
:::
736+
669737
## Troubleshooting
670738

671739
### Endpoints Not Generated

src/Foundatio.Mediator.Abstractions/MediatorExtensions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ public static IServiceCollection AddMediator(this IServiceCollection services, M
7878
if (options.LogMiddleware)
7979
registry.ShowRegisteredMiddleware();
8080

81+
if (!options.LogHandlers && !options.LogMiddleware)
82+
Console.WriteLine($"Foundatio.Mediator registered {registry.Registrations.Count} handler(s) and {registry.MiddlewareRegistrations.Count} middleware.");
83+
8184
var resolvedStrategy = strategy ?? NotificationPublishStrategy.ForeachAwait;
8285
services.TryAddSingleton<INotificationPublisher>(sp => CreatePublisher(resolvedStrategy, sp));
8386

src/Foundatio.Mediator/EndpointGenerator.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,29 @@ private static void EmitEndpointLogging(
537537
source.AppendLine($"writeLog(\" {paddedMethod} {paddedRoute} \u2192 {handlerInfo}\");");
538538
}
539539

540+
source.DecrementIndent();
541+
source.AppendLine("}");
542+
source.AppendLine("else");
543+
source.AppendLine("{");
544+
source.IncrementIndent();
545+
546+
if (hasLoggerFactory)
547+
{
548+
source.AppendLine("var endpointLogger = endpoints.ServiceProvider.GetService<ILoggerFactory>()?.CreateLogger(\"Foundatio.Mediator.Endpoints\");");
549+
source.AppendLine("if (endpointLogger != null)");
550+
source.IncrementIndent();
551+
source.AppendLine($"endpointLogger.LogInformation(\"Foundatio.Mediator mapped {entries.Count} endpoint(s).\");");
552+
source.DecrementIndent();
553+
source.AppendLine("else");
554+
source.IncrementIndent();
555+
source.AppendLine($"System.Console.WriteLine(\"Foundatio.Mediator mapped {entries.Count} endpoint(s).\");");
556+
source.DecrementIndent();
557+
}
558+
else
559+
{
560+
source.AppendLine($"System.Console.WriteLine(\"Foundatio.Mediator mapped {entries.Count} endpoint(s).\");");
561+
}
562+
540563
source.DecrementIndent();
541564
source.AppendLine("}");
542565
}

src/Foundatio.Mediator/HandlerGenerator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ private static void EmitBeforeMiddlewareResultVariables(
683683
source.AppendLine($"{m.Method.ReturnType.UnwrappedFullName}{nullableMarker} {resultVarName} = {defaultValue};");
684684

685685
// Track whether Before ran so Finally can be skipped when short-circuited
686-
if (!m.Method.ReturnType.IsHandlerResult)
686+
if (!m.Method.ReturnType.IsHandlerResult && m.Middleware.FinallyMethod != null)
687687
{
688688
source.AppendLine($"bool {m.Middleware.Identifier.ToCamelCase()}BeforeRan = false;");
689689
}
@@ -729,7 +729,7 @@ private static void EmitBeforeMiddlewareCalls(
729729
source.AppendLine($"{result}{asyncModifier}{accessor}.{m.Method.MethodName}({parameters});");
730730

731731
// Mark that Before ran so Finally knows it's safe to execute
732-
if (m.Method.HasReturnValue && !m.Method.ReturnType.IsHandlerResult)
732+
if (m.Method.HasReturnValue && !m.Method.ReturnType.IsHandlerResult && m.Middleware.FinallyMethod != null)
733733
{
734734
source.AppendLine($"{m.Middleware.Identifier.ToCamelCase()}BeforeRan = true;");
735735
}

tests/Foundatio.Mediator.Tests/BasicHandlerGenerationTests.DefaultStaticHandler_WithOTel.verified.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
Diagnostics: null,
33
GeneratorDiagnostics: null,
44
GeneratedTrees: [

tests/Foundatio.Mediator.Tests/BasicHandlerGenerationTests.EndpointGeneration.verified.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ public static partial class Tests_MediatorEndpoints
185185
writeLog("Foundatio.Mediator mapped 1 endpoint(s):");
186186
writeLog(" GET /api/widget/{id} → WidgetHandler.Handle(GetWidget)");
187187
}
188+
else
189+
{
190+
System.Console.WriteLine("Foundatio.Mediator mapped 1 endpoint(s).");
191+
}
188192
}
189193
}
190194

tests/Foundatio.Mediator.Tests/BasicHandlerGenerationTests.HandlerWithMiddlewarePipeline.verified.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
Diagnostics: null,
33
GeneratorDiagnostics: null,
44
GeneratedTrees: [

tests/Foundatio.Mediator.Tests/BasicHandlerGenerationTests.InterceptorGeneration.verified.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
Diagnostics: null,
33
GeneratorDiagnostics: null,
44
GeneratedTrees: [

tests/Foundatio.Mediator.Tests/BasicHandlerGenerationTests.ScopedDIHandler_NoOTel.verified.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
Diagnostics: null,
33
GeneratorDiagnostics: null,
44
GeneratedTrees: [

0 commit comments

Comments
 (0)