Skip to content

Commit 099bc84

Browse files
authored
Disable buffering of Blazor streaming responses (#53929)
1 parent 3e168fe commit 099bc84

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

src/Components/Endpoints/src/RazorComponentEndpointInvoker.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Microsoft.AspNetCore.Components.Endpoints.Rendering;
1010
using Microsoft.AspNetCore.Diagnostics;
1111
using Microsoft.AspNetCore.Http;
12+
using Microsoft.AspNetCore.Http.Features;
1213
using Microsoft.AspNetCore.WebUtilities;
1314
using Microsoft.Extensions.DependencyInjection;
1415
using Microsoft.Extensions.Hosting;
@@ -116,6 +117,16 @@ await EndpointHtmlRenderer.InitializeStandardComponentServicesAsync(
116117
}
117118
}
118119

120+
if (!quiesceTask.IsCompleted)
121+
{
122+
// An incomplete QuiescenceTask indicates there may be streaming rendering updates.
123+
// Disable all response buffering and compression on IIS like SignalR's ServerSentEventsServerTransport does.
124+
var bufferingFeature = context.Features.GetRequiredFeature<IHttpResponseBodyFeature>();
125+
bufferingFeature.DisableBuffering();
126+
127+
context.Response.Headers.ContentEncoding = "identity";
128+
}
129+
119130
// Importantly, we must not yield this thread (which holds exclusive access to the renderer sync context)
120131
// in between the first call to htmlContent.WriteTo and the point where we start listening for subsequent
121132
// streaming SSR batches (inside SendStreamingUpdatesAsync). Otherwise some other code might dispatch to the

src/Components/test/E2ETest/ServerRenderingTests/StreamingRenderingTest.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33

44
using System.Globalization;
55
using System.Net.Http;
6-
using System.Net.Http.Headers;
76
using System.Text;
87
using System.Text.RegularExpressions;
98
using Components.TestServer.RazorComponents;
109
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
1110
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
1211
using Microsoft.AspNetCore.E2ETesting;
12+
using Microsoft.Net.Http.Headers;
1313
using OpenQA.Selenium;
1414
using TestServer;
1515
using Xunit.Abstractions;
@@ -30,13 +30,29 @@ public override Task InitializeAsync()
3030
=> InitializeAsync(BrowserFixture.StreamingContext);
3131

3232
[Fact]
33-
public void CanRenderNonstreamingPageWithoutInjectingStreamingMarkers()
33+
public async Task CanRenderNonstreamingPageWithoutInjectingStreamingMarkersOrHeaders()
3434
{
3535
Navigate(ServerPathBase);
3636

3737
Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
3838

3939
Assert.DoesNotContain("<blazor-ssr", Browser.PageSource);
40+
41+
using var httpClient = new HttpClient();
42+
using var response = await httpClient.GetAsync(new Uri(_serverFixture.RootUri, ServerPathBase));
43+
response.EnsureSuccessStatusCode();
44+
45+
Assert.False(response.Content.Headers.Contains(HeaderNames.ContentEncoding));
46+
}
47+
48+
[Fact]
49+
public async Task DoesRenderStreamingPageWithStreamingHeadersToDisableBuffering()
50+
{
51+
using var httpClient = new HttpClient();
52+
using var response = await httpClient.GetAsync(new Uri(_serverFixture.RootUri, $"{ServerPathBase}/streaming"), HttpCompletionOption.ResponseHeadersRead);
53+
response.EnsureSuccessStatusCode();
54+
55+
Assert.Equal("identity", response.Content.Headers.ContentEncoding.Single());
4056
}
4157

4258
[Theory]

0 commit comments

Comments
 (0)