Add docs for AcBinary MVC formatters and pipeline updates Comprehensive documentation for new ASP.NET Core MVC formatters supporting AcBinary, including registration, media type, request/response flow, error handling, and future plans. Updated project and topic docs to reference MVC formatters and folder structure. Added performance planning entry for StreamPipeWriter congestion fallback. Expanded markerless schema lane rationale and updated architecture docs to reflect MVC formatter integration. Improved navigation and layering documentation. |
||
|---|---|---|
| .. | ||
| README.md | ||
README.md
MVC — AcBinary formatters
ASP.NET Core MVC InputFormatter / OutputFormatter pair for the AcBinary wire format. Works in controller-based MVC and Minimal API on .NET 9+. The wire payload is the raw byte[] produced by AcBinarySerializer.Serialize(value, opts) — bit-compatible with the single-shot byte[] API; no MVC-specific envelope.
Code:
AyCode.Services/Mvc/(AcBinaryInputFormatter,AcBinaryOutputFormatter,AcBinaryMvcBuilderExtensions) Binary serializer:../../../AyCode.Core/AyCode.Core/docs/BINARY/README.md
Registration
// Program.cs
builder.Services.AddControllers()
.AddAcBinaryFormatters(opts => {
opts.UseGeneratedCode = true;
});
AddAcBinaryFormatters inserts both formatters at index 0 of MvcOptions.InputFormatters / OutputFormatters — AcBinary wins content-negotiation when the client's Accept header allows.
Media Type
application/vnd.acbinary (vendor tree, registered with the IANA pattern but not yet IANA-listed). The same media type is sent on both request (Content-Type) and response.
Override via SupportedMediaTypes.Add(...) on a custom formatter instance if a project-specific type is needed.
Request flow (InputFormatter)
HttpContext.Request.Body (Stream)
→ PipeReader.Create(Body) (PipeReader)
→ drain-loop on calling thread:
while (true) {
result = await reader.ReadAsync(ct);
foreach (segment in result.Buffer) input.Feed(segment.Span);
reader.AdvanceTo(result.Buffer.End);
if (result.IsCompleted) break;
}
input.Complete();
↑ background Task.Run feeds AcBinaryDeserializer.Deserialize(input, ModelType, opts)
→ ModelType instance → InputFormatterResult.Success
The drain-loop is inline in the formatter — the serializer surface ends at AsyncPipeReaderInput. Any I/O-specific draining (PipeReader, NamedPipe, FileStream, custom transport) is the consumer's responsibility.
Response flow (OutputFormatter)
HttpContext.Response.Body (Stream)
→ PipeWriter.Create(Body) (PipeWriter)
→ AcBinarySerializer.SerializeChunked(value, ObjectType, writer, opts)
(raw mode — pure AcBinary bytes, no [201][UINT16] framing)
→ await pipeWriter.CompleteAsync()
SerializeChunked (not SerializeChunkedFramed) — the wire is a single self-contained AcBinary blob, identical to Serialize(value, opts) → byte[]. No multiplexed framing on the HTTP body.
Error model
Deserialization failure → ModelState.TryAddModelError(ModelName, ex.Message) → InputFormatterResult.Failure(). ASP.NET pipeline emits 400 Bad Request with application/problem+json (RFC 7807) — not an AcBinary-encoded error. The client reads the error body as JSON.
OperationCanceledException (when RequestAborted is signalled) is rethrown so the pipeline aborts the response cleanly.
Cancellation
HttpContext.RequestAborted flows into both formatters. The InputFormatter passes it to PipeReader.ReadAsync and Task.Run; the OutputFormatter calls cancellationToken.ThrowIfCancellationRequested() after CompleteAsync. Mid-request abort releases all pooled resources via the using and finally blocks.
What the formatter does NOT include
- No Stream-async API in the binary core —
AcBinarySerializerhas noSerializeAsync(Stream, T)method. The formatter is the wrapper. (SeeBINARY_TODO.md#accore-bin-t-t8k3— parked.) - No options thread-safety guard —
AcBinarySerializerOptionsis currently mutable; if registered as a DI singleton withConfigure<>it is fine becauseConfigureis read-only at runtime, but raw-shared mutable instances across concurrent requests are unsafe. (SeeBINARY_ISSUES.md#accore-bin-i-l8n5andBINARY_TODO.md#accore-bin-t-b7h4.) - No OpenAPI metadata helpers —
Microsoft.AspNetCore.OpenApi/Swashbuckle.AspNetCorepick upSupportedMediaTypesautomatically; no extra integration needed.
Future work
The formatter currently lives in AyCode.Services (alongside the SignalR transport). The intent is to extract it into its own NuGet package — AyCode.AspNetCore.Mvc.Formatters.AcBinary — when the binary serializer is moved to a dedicated solution. No code change required at extraction time; only project-file split.