瀏覽代碼

Disable buffering of Blazor streaming responses (#53929)

Stephen Halter 2 年之前
父節點
當前提交
099bc84939

+ 11 - 0
src/Components/Endpoints/src/RazorComponentEndpointInvoker.cs

@@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Antiforgery;
 using Microsoft.AspNetCore.Components.Endpoints.Rendering;
 using Microsoft.AspNetCore.Diagnostics;
 using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
 using Microsoft.AspNetCore.WebUtilities;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
@@ -116,6 +117,16 @@ internal partial class RazorComponentEndpointInvoker : IRazorComponentEndpointIn
             }
         }
 
+        if (!quiesceTask.IsCompleted)
+        {
+            // An incomplete QuiescenceTask indicates there may be streaming rendering updates.
+            // Disable all response buffering and compression on IIS like SignalR's ServerSentEventsServerTransport does.
+            var bufferingFeature = context.Features.GetRequiredFeature<IHttpResponseBodyFeature>();
+            bufferingFeature.DisableBuffering();
+
+            context.Response.Headers.ContentEncoding = "identity";
+        }
+
         // Importantly, we must not yield this thread (which holds exclusive access to the renderer sync context)
         // in between the first call to htmlContent.WriteTo and the point where we start listening for subsequent
         // streaming SSR batches (inside SendStreamingUpdatesAsync). Otherwise some other code might dispatch to the

+ 18 - 2
src/Components/test/E2ETest/ServerRenderingTests/StreamingRenderingTest.cs

@@ -3,13 +3,13 @@
 
 using System.Globalization;
 using System.Net.Http;
-using System.Net.Http.Headers;
 using System.Text;
 using System.Text.RegularExpressions;
 using Components.TestServer.RazorComponents;
 using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
 using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
 using Microsoft.AspNetCore.E2ETesting;
+using Microsoft.Net.Http.Headers;
 using OpenQA.Selenium;
 using TestServer;
 using Xunit.Abstractions;
@@ -30,13 +30,29 @@ public class StreamingRenderingTest : ServerTestBase<BasicTestAppServerSiteFixtu
         => InitializeAsync(BrowserFixture.StreamingContext);
 
     [Fact]
-    public void CanRenderNonstreamingPageWithoutInjectingStreamingMarkers()
+    public async Task CanRenderNonstreamingPageWithoutInjectingStreamingMarkersOrHeaders()
     {
         Navigate(ServerPathBase);
 
         Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
 
         Assert.DoesNotContain("<blazor-ssr", Browser.PageSource);
+
+        using var httpClient = new HttpClient();
+        using var response = await httpClient.GetAsync(new Uri(_serverFixture.RootUri, ServerPathBase));
+        response.EnsureSuccessStatusCode();
+
+        Assert.False(response.Content.Headers.Contains(HeaderNames.ContentEncoding));
+    }
+
+    [Fact]
+    public async Task DoesRenderStreamingPageWithStreamingHeadersToDisableBuffering()
+    {
+        using var httpClient = new HttpClient();
+        using var response = await httpClient.GetAsync(new Uri(_serverFixture.RootUri, $"{ServerPathBase}/streaming"), HttpCompletionOption.ResponseHeadersRead);
+        response.EnsureSuccessStatusCode();
+
+        Assert.Equal("identity", response.Content.Headers.ContentEncoding.Single());
     }
 
     [Theory]