Add StreamOne/StreamMany/StreamAggregate typed streaming result types#4260
Merged
jeremydmiller merged 3 commits intomasterfrom Apr 17, 2026
Merged
Add StreamOne/StreamMany/StreamAggregate typed streaming result types#4260jeremydmiller merged 3 commits intomasterfrom
jeremydmiller merged 3 commits intomasterfrom
Conversation
Marten.AspNetCore already has WriteSingle/WriteArray/WriteLatest extension helpers that stream raw JSON directly to an HttpResponse. These three new types wrap that behavior as typed endpoint return values for Minimal API (and Wolverine.Http, or any framework that dispatches IResult): StreamOne<T>(IQueryable<T>) -> WriteSingle<T>, 200/404 StreamMany<T>(IQueryable<T>) -> WriteArray<T>, always 200 (empty []) StreamAggregate<T>(session, id) -> WriteLatest<T>, 200/404 Each implements IResult so ASP.NET Minimal API dispatches it via ExecuteAsync, and IEndpointMetadataProvider so Swashbuckle, NSwag, and the built-in OpenAPI generator see the right response shape (Produces<T> / Produces<IReadOnlyList<T>> / Produces(404)). OnFoundStatus and ContentType are init-only properties for customization. - Types live in Marten.AspNetCore namespace alongside QueryableExtensions - IssueService now also maps Minimal-API endpoints under /minimal/... for test coverage - New streaming_result_types_tests.cs asserts all three types (hit/miss, custom status, custom content type, OpenAPI metadata) via Alba Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The "404 on miss?" column's pipes did not line up with the header row because the StreamMany row's value "no (empty array = 200)" was longer than the header. Pad header/separator/other rows to match for MD060. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds two-arity generic variants of the streaming IResult types that
wrap Marten's ICompiledQuery<TDoc, TOut>:
StreamOne<TDoc, TOut>(IQuerySession, ICompiledQuery<TDoc, TOut>)
-> WriteOne, 200/404
StreamMany<TDoc, TOut>(IQuerySession, ICompiledQuery<TDoc, TOut>)
-> WriteArray, always 200
These sit alongside the existing single-arity IQueryable-based types
(StreamOne<T>, StreamMany<T>). Each implements IResult and
IEndpointMetadataProvider, advertising 200: TOut (and 404 for StreamOne)
in OpenAPI metadata.
- Two new Marten.AspNetCore types (StreamOneCompiled.cs, StreamManyCompiled.cs)
- IssueService minimal endpoints exercise IssueById and OpenIssues compiled queries
- Six new Alba tests: hit, 404, custom OnFoundStatus, metadata shape, and
JSON array body for the list overload
- Docs updated with a compiled-query example section
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
jeremydmiller
added a commit
to JasperFx/wolverine
that referenced
this pull request
Apr 20, 2026
The streaming result types originally landed locally in Wolverine.Http.Marten in this branch. They've since shipped upstream in Marten.AspNetCore 8.31.0 (via JasperFx/marten#4260 — the same types, lifted to live next to the existing WriteSingle/WriteArray/WriteLatest helpers and usable from any Minimal-API endpoint, not just Wolverine.Http). This commit: - Bumps Marten + Marten.AspNetCore 8.28.0 → 8.31.0 and JasperFx.Events 1.27.0 → 1.28.1 in Directory.Packages.props - Deletes the local StreamOne/StreamMany/StreamAggregate types from Wolverine.Http.Marten - Switches the WolverineWebApi sample endpoints and the test file to use Marten.AspNetCore.StreamOne/StreamMany/StreamAggregate - Updates docs/guide/http/marten.md to point at Marten.AspNetCore as the source of the types and call out that no Wolverine-specific code is required — the types implement IResult and Wolverine.Http dispatches them through its existing ResultWriterPolicy The existing tests carry over unchanged — they pass against the upstream types because the public surface is identical (same constructors, same init-only OnFoundStatus/ContentType, same OpenAPI metadata via IEndpointMetadataProvider). Verified with `dotnet test`: all 12 streaming_endpoints tests + 20 related Marten tests (compiled_query_writer, using_aggregate_handler_workflow) pass against the new packages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This was referenced Apr 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Marten.AspNetCorealready shipsWriteSingle/WriteArray/WriteLatestextension helpers that stream raw JSON directly to anHttpResponse. This PR adds three typed endpoint return values that wrap that behavior for Minimal API endpoints (and any framework that dispatchesIResult, e.g. Wolverine.Http).StreamOne<T>IQueryable<T>— regular Marten document queryTStreamMany<T>IQueryable<T>— regular Marten document queryT[][])StreamAggregate<T>IDocumentSession+ stream id — event-sourcedTWhy
WriteSingle(HttpContext)/WriteArray(HttpContext)/WriteLatest(HttpContext)are already great at what they do, but endpoint authors have to manually wire the result up and lose typed return values (and therefore lose good OpenAPI metadata). These wrappers give Minimal API and Wolverine.Http users a concise, typed alternative that still gets raw-JSON-from-the-database streaming.Design
IResult(so ASP.NET Minimal API dispatches it viaExecuteAsync) andIEndpointMetadataProvider(so Swashbuckle, NSwag, and the built-in OpenAPI generator see the right response shape —Produces<T>/Produces<IReadOnlyList<T>>/Produces(404)).ExecuteAsyncdelegates to the existing extension helpers — zero behavioral drift.OnFoundStatus(default 200) andContentType(defaultapplication/json) are init-only properties so endpoints can customize e.g.201 Createdor a vendor-specific content type.StreamAggregate<T>requiresIDocumentSession(mirroring the existingWriteLatestconstraint).Example
```csharp
app.MapGet("/issues/{id:guid}",
(Guid id, IQuerySession session) =>
new StreamOne(session.Query().Where(x => x.Id == id)));
app.MapGet("/issues/open",
(IQuerySession session) =>
new StreamMany(session.Query().Where(x => x.Open)));
app.MapGet("/orders/{id:guid}",
(Guid id, IDocumentSession session) =>
new StreamAggregate(session, id));
```
Scope
Test plan
🤖 Generated with Claude Code