Skip to content

Conversation

@sebastienros
Copy link
Owner

@sebastienros sebastienros commented Feb 2, 2026

Summary of Changes

This PR adds IAsyncDisposable support to TextWriterFluidOutput and updates all usages to use await using instead of using to ensure fully asynchronous disposal.

Key changes:

  • Added IAsyncDisposable interface implementation to TextWriterFluidOutput with DisposeAsync() method
  • Updated all callers to use await using pattern:
    • FluidRendering.cs (MVC View Engine)
    • FluidViewRenderer.cs (View Engine - both RenderViewAsync and RenderPartialAsync)
    • FluidOutputExtensions.cs (3 extension methods)
    • FluidTemplateExtensions.cs
    • ActionViewResult.cs (Minimal APIs)
  • Added comprehensive unit tests (TextWriterFluidOutputTests.cs - 1073 lines)
  • Added integration tests (FluidOutputIntegrationTests.cs - 498 lines)

Motivation and Context

Fixes #919

ASP.NET Core disables synchronous I/O by default (IHttpBodyControlFeature.AllowSynchronousIO = false). The v3.0.0-beta4 release introduced TextWriterFluidOutput which used synchronous Dispose() that internally called FlushCore() with synchronous writes. This caused System.InvalidOperationException: Synchronous operations are disallowed errors when rendering Liquid templates in ASP.NET Core applications, particularly when response compression (e.g., Brotli) was enabled.

How the Changes Were Tested

  • Added TextWriterFluidOutputTests.cs with comprehensive unit tests covering:

    • DisposeAsync() behavior and buffer cleanup
    • Async flushing and disposal patterns
    • Leave-open writer scenarios
    • Edge cases around buffer management
  • Added FluidOutputIntegrationTests.cs with integration tests covering:

    • End-to-end async rendering scenarios
    • Verification that async disposal path is used correctly

Screenshots

N/A - Internal API change, no UI impact.

Checklist

  • Code compiles without errors
  • Implemented IAsyncDisposable on TextWriterFluidOutput
  • Updated all using statements to await using for async disposal
  • Added unit tests for async disposal
  • Added integration tests
  • Maintains backward compatibility (synchronous Dispose() still available)
  • Cross-platform support via #if NETSTANDARD2_0 conditional compilation

@sebastienros sebastienros changed the title Based on the changes, the fix adds IAsyncDisposable implementation to TextWriterFluidOutput with a DisposeAsync() method that properly handles async flushing. **PR Title:** fix: add IAsyncDisposable to TextWriterFluidOutput for async flush This title: - Uses conventional commit format (fix:) - Is under 72 characters (54 chars) - Describes the specific change (adding async disposable support) - Relates to issue #919 about the dispose requiring force sync Fix: TextWriterFluidOutput.Dispose() requires force sync (#919) Feb 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: TextWriterFluidOutput.Dispose() requires force sync

1 participant