.NET 11 ReadOnlySequenceStream lets a Stream-based consumer read segmented memory without first flattening it into a contiguous array. When that memory comes from a PipeReader, finish the awaited consumption before calling AdvanceTo or completing the reader. The adapter borrows the sequence; it does not extend the lifetime of the pipe buffers. A small, verified console demo below shows the safe ordering, a deliberately broken ordering, and the owning-copy alternative.
Table of Contents
Use .NET 11 ReadOnlySequenceStream within the read lifetime
The useful boundary is the lifetime of one valid sequence. After your framing code has identified the bytes to pass downstream, wrap that sequence, await the consumer, dispose the adapter, and only then release the read. The following pattern assumes buffer is the selected payload and destination accepts the complete payload; framing and destination creation belong to your application.
using System.Buffers;
using (var source = new ReadOnlySequenceStream(buffer))
{
await source.CopyToAsync(destination, cancellationToken);
}
reader.AdvanceTo(buffer.End);
Awaiting the operation keeps the source available until CopyToAsync has finished using it. AdvanceTo consumes the whole selected buffer here, so this exact position is appropriate only when all of those bytes were handled. If a read also contains a partial next message, calculate the consumed and examined positions from your framing logic instead of copying this final line unchanged.
This adapter represents the bytes already present in the sequence. Reaching its end does not fetch another PipeReader read, and it does not mean the producer has finished. A consumer that expects an entire file or document must receive that complete framed payload, rather than an arbitrary network-read chunk. For an application that already accepts a Stream over a continuing input, consider the appropriate live-stream integration instead of manufacturing a sequence snapshot.
Run the console proof on the pinned RC1 SDK
The proof was executed on Windows on October 2, 2026 with SDK 11.0.100-rc.1.26425.128, runtime 11.0.0, and the framework API from System.Memory, Version=11.0.0.0. It restored, built, and ran successfully, with zero build warnings and errors. This is preview-version evidence; repeat the checks when moving to another preview or the final release.
The demo targets net11.0 and uses a FrameworkReference to Microsoft.AspNetCore.App to obtain System.IO.Pipelines. It is a console program, so no browser, web server, Azure account, Docker installation, or external NuGet package is involved. Its NuGet.Config clears package feeds, and the installed SDK must already supply the needed framework packs.
Get-ChildItem -Recurse -Filter *.ps1 | Unblock-File
powershell -NoProfile -ExecutionPolicy Bypass -File .\Verify-SequenceStream.ps1
Run those commands from the extracted folder containing the script. The verifier selects the SDK, restores and builds the project, executes it, and checks the saved receipt. Each invocation writes a timestamped evidence directory, so keep the corresponding console.txt and receipt.json together.

See why early completion invalidates the adapter
The proof creates a 128-byte payload in two segments and holds a downstream consumer behind an explicit asynchronous gate. In the safe case, the consumer finishes while the pipe still owns both rented buffers; afterward, completion returns the segments. This deterministic gate exposes the lifetime ordering without relying on an accidental timing race.
The broken case advances and completes the pipe while the consumer is still waiting. In the recorded Windows run, releasing the consumer then produced an InvalidOperationException saying that enumeration could not reach the end position. The harness expects and checks that negative result, so it counts as successful detection of unsafe access rather than a failed demo.
A separate negative test uses directly rented memory to isolate buffer reuse from pipe-segment invalidation. Its custom pool fills returned bytes with 0xDD, and the delayed reader observes that marker. This controlled diagnostic makes the ownership error visible; it does not predict what every production pool will write or which exception a real application will throw.

Choose borrowed memory or an owning copy deliberately
Use the borrowed adapter when downstream work can finish inside the read lifetime. If you need to enqueue work, return a stream to another layer, or let consumption continue after AdvanceTo, give that work independently owned storage. The demo verifies this alternative by making a copy, completing the pipe, and then reading the copy successfully.
byte[] owned = buffer.ToArray();
reader.AdvanceTo(buffer.End);
await reader.CompleteAsync();
using var source = new MemoryStream(owned, writable: false);
// This storage is independent of the completed pipe.
await source.CopyToAsync(destination, cancellationToken);
The extra allocation is intentional: it buys a lifetime independent of the pipe. Bound the payload before making the copy, and choose a different storage strategy for large messages. If destination writes can fail partway through, decide whether retry is safe; reusing the input does not undo a partially written external result.
The adapter is read-only and non-seekable in the tested RC1 implementation. The demo verifies that Length throws NotSupportedException and that reads after disposal throw ObjectDisposedException. Check a downstream library for requirements such as seeking or querying Length before replacing a MemoryStream with this adapter.
Disposing ReadOnlySequenceStream does not return the source pool buffers. The pipe or other memory owner remains responsible for them, which the demo verifies separately. Dispose the adapter and complete the reader at their respective ownership boundaries rather than treating one operation as a substitute for the other.
Handle cancellation, limits, and partial reads
Pass cancellation to the downstream operation and keep reader completion in an owning outer cleanup path. For an ASP.NET Core endpoint, propagate request cancellation through downstream API operations. Cancellation and exceptions can leave the destination partially written; once you abort the read, ensure no background consumer retains the borrowed sequence. The recorded test covers an already-canceled ReadAsync, while cancellation during a real destination write still needs an integration test with that destination.
A completed producer may leave final bytes in its last read. Process the remaining data before deciding that completion ends your read loop. Also enforce message-size and waiting-time limits: retaining a borrowed read while an unbounded or stalled consumer runs can keep pooled memory occupied and interfere with backpressure.
The proof deliberately uses a tiny fixed payload to verify ownership, not throughput. ReadOnlySequenceStream removes the need for an initial contiguous source copy; ordinary reads still copy into their destination buffers, and downstream code may allocate. Neither the screenshots nor the receipt establishes a speedup, an allocation benchmark, or end-to-end zero-copy HTTP.
For a real integration, verify both the payload result and the ownership transition. Test a segmented input, a delayed consumer, an incomplete frame, final buffered data, destination failure, and cancellation. If a layer needs to outlive the read, make that ownership transfer explicit before adopting the adapter.
References
- Microsoft: .NET 11 in-memory stream adapters — the supported adapter purpose and removal of an initial flattening copy.
- Microsoft: System.IO.Pipelines — read-buffer lifetime, consumed/examined positions, completion, and common errors.
- .NET runtime: release-pinned ReadOnlySequenceStream implementation — RC1 stream capabilities, read/copy behavior, cancellation, and disposal.
Demo source code: View the complete runnable example on GitHub.
Found this useful? Support more practical developer content.