diff --git a/src/Components/.vscode/launch.json b/src/Components/.vscode/launch.json
index 39daed7ea684be6d12d008b67f74de1fb0eb5ce8..2d3a3106f85e436f9c7900fe72bae6558b92719b 100644
--- a/src/Components/.vscode/launch.json
+++ b/src/Components/.vscode/launch.json
@@ -1,6 +1,12 @@
 {
   "version": "0.2.0",
   "configurations": [
+    {
+      "name": ".NET Core Attach",
+      "type": "coreclr",
+      "request": "attach",
+      "processId": "${command:pickProcess}"
+    },
     {
       "name": "BlazorServerApp",
       "type": "coreclr",
diff --git a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj
index 1bb8e17fcfaf44e84c3966c4ae2e569c29e0fc00..0b1af77eda8acce6af74e144494d2a572b722b6d 100644
--- a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj
+++ b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj
@@ -84,6 +84,10 @@
     <Compile Include="$(RepoRoot)src\Shared\Components\WebAssemblyComponentMarker.cs" />
   </ItemGroup>
 
+  <ItemGroup>
+    <Compile Include="$(RepoRoot)src\Shared\SignalR\*.cs" />
+  </ItemGroup>
+
   <ItemGroup>
     <AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
       <_Parameter1>Microsoft.AspNetCore.E2ETesting.TestTrimmedApps</_Parameter1>
diff --git a/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs b/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs
index 520c90d59b4fc25bdeea7084da792d23e4eb2e58..bbbdece67bf5511c0fac221a553aee7efbbd4b03 100644
--- a/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs
+++ b/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs
@@ -7,47 +7,49 @@ using System.Net.Http;
 using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
+using Microsoft.AspNetCore.SignalR.Tests;
 using Microsoft.AspNetCore.SignalR.Client;
 using Microsoft.AspNetCore.Testing;
+using System.Collections.Concurrent;
 using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Testing;
 using TestServer;
 using Xunit;
+using Ignitor;
+using System.Collections.Generic;
 using Xunit.Abstractions;
+using System.Diagnostics;
 
 namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
 {
     [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/19666")]
-    public class ComponentHubReliabilityTest : IgnitorTest<ServerStartup>
+    public class ComponentHubReliabilityTest : FunctionalTestBase
     {
-        public ComponentHubReliabilityTest(BasicTestAppServerSiteFixture<ServerStartup> serverFixture, ITestOutputHelper output)
-            : base(serverFixture, output)
-        {
-        }
+        private static readonly TimeSpan DefaultTimeout = Debugger.IsAttached ? TimeSpan.MaxValue : TimeSpan.FromSeconds(30);
 
-        protected override async Task InitializeAsync()
-        {
-            await base.InitializeAsync();
+        protected BlazorClient Client { get; private set; }
 
-            var rootUri = ServerFixture.RootUri;
-            var baseUri = new Uri(rootUri, "/subdir");
-            var client = new HttpClient();
-            for (var i = 0; i < 10; i++)
-            {
-                try
-                {
-                    var response = await client.GetAsync(baseUri + "/_negotiate");
-                    if (response.StatusCode == HttpStatusCode.OK)
-                    {
-                        break;
-                    }
-                }
-                catch
-                {
-                    await Task.Delay(500);
-                    throw;
-                }
-            }
+        protected ITestOutputHelper Output { get; }
+
+        protected TimeSpan Timeout { get; set; } = DefaultTimeout;
 
+        protected IReadOnlyCollection<CapturedRenderBatch> Batches => Client?.Operations?.Batches;
+
+        protected IReadOnlyCollection<string> DotNetCompletions => Client?.Operations?.DotNetCompletions;
+
+        protected IReadOnlyCollection<string> Errors => Client?.Operations?.Errors;
+
+        protected IReadOnlyCollection<CapturedJSInteropCall> JSInteropCalls => Client?.Operations?.JSInteropCalls;
+
+        public ComponentHubReliabilityTest(ITestOutputHelper output)
+        {
+            Output = output;
+            Client = new BlazorClient()
+            {
+                CaptureOperations = true,
+                DefaultOperationTimeout = Timeout,
+            };
+            Client.LoggerProvider = new XunitLoggerProvider(Output);
         }
 
         [Fact]
@@ -56,24 +58,30 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
             // Arrange
             var expectedError = "The circuit host '.*?' has already been initialized.";
 
-            var rootUri = ServerFixture.RootUri;
-            var baseUri = new Uri(rootUri, "/subdir");
-            await ConnectAutomaticallyAndWait(baseUri);
-
-            var descriptors = await Client.GetPrerenderDescriptors(baseUri);
-
-            // Act
-            await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
-                "StartCircuit",
-                baseUri,
-                baseUri + "/home",
-                descriptors,
-                null));
-
-            // Assert
-            var actualError = Assert.Single(Errors);
-            Assert.Matches(expectedError, actualError);
-            Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information);
+            await using (var server = await StartServer<ServerStartup>())
+            {
+                ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new();
+                server.ServerLogged += (LogRecord record) => logs.Enqueue(record);
+
+                var baseUri = new Uri($"{server.Url}/subdir");
+                Assert.True(await Client.ConnectAsync(baseUri), "Couldn't connect to the app");
+                Assert.Single(Batches);
+
+                var descriptors = await Client.GetPrerenderDescriptors(baseUri);
+
+                // Act
+                await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
+                    "StartCircuit",
+                    baseUri,
+                    baseUri + "/home",
+                    descriptors,
+                    null));
+
+                // Assert
+                var actualError = Assert.Single(Errors);
+                Assert.Matches(expectedError, actualError);
+                Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information);
+            }
         }
 
         [Fact]
@@ -81,18 +89,20 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
         {
             // Arrange
             var expectedError = "The uris provided are invalid.";
-            var rootUri = ServerFixture.RootUri;
-            var uri = new Uri(rootUri, "/subdir");
-            Assert.True(await Client.ConnectAsync(uri, connectAutomatically: false), "Couldn't connect to the app");
-            var descriptors = await Client.GetPrerenderDescriptors(uri);
-
-            // Act
-            await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync("StartCircuit", null, null, descriptors, null));
-
-            // Assert
-            var actualError = Assert.Single(Errors);
-            Assert.Matches(expectedError, actualError);
-            Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information);
+            await using (var server = await StartServer<ServerStartup>())
+            {
+                var rootUri = server.Url;
+                var uri = new Uri($"{rootUri}/subdir");
+                Assert.True(await Client.ConnectAsync(uri, connectAutomatically: false), "Couldn't connect to the app");
+                var descriptors = await Client.GetPrerenderDescriptors(uri);
+
+                // Act
+                await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync("StartCircuit", null, null, descriptors, null));
+
+                // Assert
+                var actualError = Assert.Single(Errors);
+                Assert.Matches(expectedError, actualError);
+            }
         }
 
         // This is a hand-chosen example of something that will cause an exception in creating the circuit host.
@@ -103,20 +113,23 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
         {
             // Arrange
             var expectedError = "The circuit failed to initialize.";
-            var rootUri = ServerFixture.RootUri;
-            var uri = new Uri(rootUri, "/subdir");
-            Assert.True(await Client.ConnectAsync(uri, connectAutomatically: false), "Couldn't connect to the app");
-            var descriptors = await Client.GetPrerenderDescriptors(uri);
-
-            // Act
-            //
-            // These are valid URIs by the BaseUri doesn't contain the Uri - so it fails to initialize.
-            await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync("StartCircuit", uri, "http://example.com", descriptors, null), Timeout);
-
-            // Assert
-            var actualError = Assert.Single(Errors);
-            Assert.Matches(expectedError, actualError);
-            Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information);
+
+            await using (var server = await StartServer<ServerStartup>())
+            {
+                var rootUri = server.Url;
+                var uri = new Uri($"{rootUri}/subdir");
+                Assert.True(await Client.ConnectAsync(uri, connectAutomatically: false), "Couldn't connect to the app");
+                var descriptors = await Client.GetPrerenderDescriptors(uri);
+
+                // Act
+                //
+                // These are valid URIs by the BaseUri doesn't contain the Uri - so it fails to initialize.
+                await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync("StartCircuit", uri, "http://example.com", descriptors, null), Timeout);
+
+                // Assert
+                var actualError = Assert.Single(Errors);
+                Assert.Matches(expectedError, actualError);
+            }
         }
 
         [Fact]
@@ -124,25 +137,31 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
         {
             // Arrange
             var expectedError = "Circuit not initialized.";
-            var rootUri = ServerFixture.RootUri;
-            var baseUri = new Uri(rootUri, "/subdir");
-            Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false));
-            Assert.Empty(Batches);
-
-            // Act
-            await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
-                "BeginInvokeDotNetFromJS",
-                "",
-                "",
-                "",
-                0,
-                ""));
-
-            // Assert
-            var actualError = Assert.Single(Errors);
-            Assert.Equal(expectedError, actualError);
-            Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information);
-            Assert.Contains(Logs, l => (l.LogLevel, l.Message) == (LogLevel.Debug, "Call to 'BeginInvokeDotNetFromJS' received before the circuit host initialization"));
+            await using (var server = await StartServer<ServerStartup>())
+            {
+                ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new();
+                server.ServerLogged += (LogRecord record) => logs.Enqueue(record);
+                var rootUri = server.Url;
+                var baseUri = new Uri($"{rootUri}/subdir");
+                Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false));
+                Assert.Empty(Batches);
+
+                // Act
+                await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
+                    "BeginInvokeDotNetFromJS",
+                    "",
+                    "",
+                    "",
+                    0,
+                    ""));
+
+                // Assert
+                var actualError = Assert.Single(Errors);
+                Assert.Equal(expectedError, actualError);
+                Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information);
+                Assert.Contains(logs, l =>
+                    l.Write.LogLevel == LogLevel.Debug && l.Write.Message.Contains("Call to 'BeginInvokeDotNetFromJS' received before the circuit host initialization"));
+            }
         }
 
         [Fact]
@@ -151,23 +170,28 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
         {
             // Arrange
             var expectedError = "Circuit not initialized.";
-            var rootUri = ServerFixture.RootUri;
-            var baseUri = new Uri(rootUri, "/subdir");
-            Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false));
-            Assert.Empty(Batches);
-
-            // Act
-            await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
-                "EndInvokeJSFromDotNet",
-                3,
-                true,
-                "[]"), Timeout);
-
-            // Assert
-            var actualError = Assert.Single(Errors);
-            Assert.Equal(expectedError, actualError);
-            Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information);
-            Assert.Contains(Logs, l => (l.LogLevel, l.Message) == (LogLevel.Debug, "Call to 'EndInvokeJSFromDotNet' received before the circuit host initialization"));
+            await using (var server = await StartServer<ServerStartup>())
+            {
+                ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new();
+                server.ServerLogged += (LogRecord record) => logs.Enqueue(record);
+                var rootUri = server.Url;
+                var baseUri = new Uri($"{rootUri}/subdir");
+                Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false));
+                Assert.Empty(Batches);
+
+                // Act
+                await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
+                    "EndInvokeJSFromDotNet",
+                    3,
+                    true,
+                    "[]"), Timeout);
+
+                // Assert
+                var actualError = Assert.Single(Errors);
+                Assert.Equal(expectedError, actualError);
+                Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information);
+                Assert.Contains(logs, l => l.Write.LogLevel == LogLevel.Debug && l.Write.Message.Contains("Call to 'EndInvokeJSFromDotNet' received before the circuit host initialization"));
+            }
         }
 
         [Fact]
@@ -175,22 +199,27 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
         {
             // Arrange
             var expectedError = "Circuit not initialized.";
-            var rootUri = ServerFixture.RootUri;
-            var baseUri = new Uri(rootUri, "/subdir");
-            Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false));
-            Assert.Empty(Batches);
-
-            // Act
-            await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
-                "DispatchBrowserEvent",
-                "",
-                ""));
-
-            // Assert
-            var actualError = Assert.Single(Errors);
-            Assert.Equal(expectedError, actualError);
-            Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information);
-            Assert.Contains(Logs, l => (l.LogLevel, l.Message) == (LogLevel.Debug, "Call to 'DispatchBrowserEvent' received before the circuit host initialization"));
+            await using (var server = await StartServer<ServerStartup>())
+            {
+                ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new();
+                server.ServerLogged += (LogRecord record) => logs.Enqueue(record);
+                var rootUri = server.Url;
+                var baseUri = new Uri($"{rootUri}/subdir");
+                Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false));
+                Assert.Empty(Batches);
+
+                // Act
+                await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
+                    "DispatchBrowserEvent",
+                    "",
+                    ""));
+
+                // Assert
+                var actualError = Assert.Single(Errors);
+                Assert.Equal(expectedError, actualError);
+                Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information);
+                Assert.Contains(logs, l => l.Write.LogLevel == LogLevel.Debug && l.Write.Message.Contains("Call to 'DispatchBrowserEvent' received before the circuit host initialization"));
+            }
         }
 
         [Fact]
@@ -198,22 +227,27 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
         {
             // Arrange
             var expectedError = "Circuit not initialized.";
-            var rootUri = ServerFixture.RootUri;
-            var baseUri = new Uri(rootUri, "/subdir");
-            Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false));
-            Assert.Empty(Batches);
-
-            // Act
-            await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
-                "OnRenderCompleted",
-                5,
-                null));
-
-            // Assert
-            var actualError = Assert.Single(Errors);
-            Assert.Equal(expectedError, actualError);
-            Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information);
-            Assert.Contains(Logs, l => (l.LogLevel, l.Message) == (LogLevel.Debug, "Call to 'OnRenderCompleted' received before the circuit host initialization"));
+            await using (var server = await StartServer<ServerStartup>())
+            {
+                ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new();
+                server.ServerLogged += (LogRecord record) => logs.Enqueue(record);
+                var rootUri = server.Url;
+                var baseUri = new Uri($"{rootUri}/subdir");
+                Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false));
+                Assert.Empty(Batches);
+
+                // Act
+                await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
+                    "OnRenderCompleted",
+                    5,
+                    null));
+
+                // Assert
+                var actualError = Assert.Single(Errors);
+                Assert.Equal(expectedError, actualError);
+                Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information);
+                Assert.Contains(logs, l => l.Write.LogLevel == LogLevel.Debug && l.Write.Message.Contains("Call to 'OnRenderCompleted' received before the circuit host initialization"));
+            }
         }
 
         [Fact]
@@ -221,22 +255,27 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
         {
             // Arrange
             var expectedError = "Circuit not initialized.";
-            var rootUri = ServerFixture.RootUri;
-            var baseUri = new Uri(rootUri, "/subdir");
-            Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false));
-            Assert.Empty(Batches);
-
-            // Act
-            await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
-                "OnLocationChanged",
-                baseUri.AbsoluteUri,
-                false));
-
-            // Assert
-            var actualError = Assert.Single(Errors);
-            Assert.Equal(expectedError, actualError);
-            Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information);
-            Assert.Contains(Logs, l => (l.LogLevel, l.Message) == (LogLevel.Debug, "Call to 'OnLocationChanged' received before the circuit host initialization"));
+            await using (var server = await StartServer<ServerStartup>())
+            {
+                ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new();
+                server.ServerLogged += (LogRecord record) => logs.Enqueue(record);
+                var rootUri = server.Url;
+                var baseUri = new Uri($"{rootUri}/subdir");
+                Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false));
+                Assert.Empty(Batches);
+
+                // Act
+                await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync(
+                    "OnLocationChanged",
+                    baseUri.AbsoluteUri,
+                    false));
+
+                // Assert
+                var actualError = Assert.Single(Errors);
+                Assert.Equal(expectedError, actualError);
+                Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information);
+                Assert.Contains(logs, l => l.Write.LogLevel == LogLevel.Debug && l.Write.Message.Contains("Call to 'OnLocationChanged' received before the circuit host initialization"));
+            }
         }
 
         [Fact]
@@ -247,28 +286,34 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
                 "For more details turn on detailed exceptions by setting 'DetailedErrors: true' in 'appSettings.Development.json' or set 'CircuitOptions.DetailedErrors'. " +
                 "Location change to 'http://example.com' failed.";
 
-            var rootUri = ServerFixture.RootUri;
-            var baseUri = new Uri(rootUri, "/subdir");
-            await ConnectAutomaticallyAndWait(baseUri);
-
-            // Act
-            await Client.ExpectCircuitError(() => Client.HubConnection.SendAsync(
-                "OnLocationChanged",
-                "http://example.com",
-                false));
-
-            // Assert
-            var actualError = Assert.Single(Errors);
-            Assert.Equal(expectedError, actualError);
-            Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information);
-
-            var entry = Assert.Single(Logs, l => l.EventId.Name == "LocationChangeFailed");
-            Assert.Equal(LogLevel.Debug, entry.LogLevel);
-            Assert.Matches("Location change to 'http://example.com' in circuit '.*' failed\\.", entry.Message);
+            await using (var server = await StartServer<ServerStartup>(expectedErrorsFilter: (WriteContext val) => true))
+            {
+                ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new();
+                server.ServerLogged += (LogRecord record) => logs.Enqueue(record);
+                var rootUri = server.Url;
+                var baseUri = new Uri($"{rootUri}/subdir");
+
+                Assert.True(await Client.ConnectAsync(baseUri));
+                Assert.Single(Batches);
+
+                // Act
+                await Client.ExpectCircuitError(() => Client.HubConnection.SendAsync(
+                    "OnLocationChanged",
+                    "http://example.com",
+                    false));
+
+                // Assert
+                var actualError = Assert.Single(Errors);
+                Assert.Equal(expectedError, actualError);
+                Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information);
+
+                var entry = Assert.Single(logs, l => l.Write.EventId.Name == "LocationChangeFailed");
+                Assert.Equal(LogLevel.Debug, entry.Write.LogLevel);
+                Assert.Matches("Location change to 'http://example.com' in circuit '.*' failed\\.", entry.Write.Message);
+            }
         }
 
         [Fact]
-        [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/19666")]
         public async Task OnLocationChanged_ReportsErrorForExceptionInUserCode()
         {
             // Arrange
@@ -276,26 +321,32 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
                 "For more details turn on detailed exceptions by setting 'DetailedErrors: true' in 'appSettings.Development.json' or set 'CircuitOptions.DetailedErrors'. " +
                 "Location change failed.";
 
-            var rootUri = ServerFixture.RootUri;
-            var baseUri = new Uri(rootUri, "/subdir");
+            await using (var server = await StartServer<ServerStartup>(expectedErrorsFilter: (WriteContext val) => true))
+            {
+                ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new();
+                server.ServerLogged += (LogRecord record) => logs.Enqueue(record);
+                var rootUri = server.Url;
+                var baseUri = new Uri($"{rootUri}/subdir");
 
-            await ConnectAutomaticallyAndWait(baseUri);
+                Assert.True(await Client.ConnectAsync(baseUri));
+                Assert.Single(Batches);
 
-            await Client.SelectAsync("test-selector-select", "BasicTestApp.NavigationFailureComponent");
+                await Client.SelectAsync("test-selector-select", "BasicTestApp.NavigationFailureComponent");
 
-            // Act
-            await Client.ExpectCircuitError(() => Client.HubConnection.SendAsync(
-                "OnLocationChanged",
-                new Uri(baseUri, "/test").AbsoluteUri,
-                false));
+                // Act
+                await Client.ExpectCircuitError(() => Client.HubConnection.SendAsync(
+                    "OnLocationChanged",
+                    new Uri(baseUri, "/test").AbsoluteUri,
+                    false));
 
-            // Assert
-            var actualError = Assert.Single(Errors);
-            Assert.Equal(expectedError, actualError);
+                // Assert
+                var actualError = Assert.Single(Errors);
+                Assert.Equal(expectedError, actualError);
 
-            var entry = Assert.Single(Logs, l => l.EventId.Name == "LocationChangeFailed");
-            Assert.Equal(LogLevel.Error, entry.LogLevel);
-            Assert.Matches($"Location change to '{new Uri(ServerFixture.RootUri, "/test")}' in circuit '.*' failed\\.", entry.Message);
+                var entry = Assert.Single(logs, l => l.Write.EventId.Name == "LocationChangeFailed");
+                Assert.Equal(LogLevel.Error, entry.Write.LogLevel);
+                Assert.Matches($"Location change to '{new Uri($"{server.Url}/test")}' in circuit '.*' failed.", entry.Write.Message);
+            }
         }
 
         [Theory]
@@ -306,7 +357,6 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
         [InlineData("render-throw")]
         [InlineData("afterrender-sync-throw")]
         [InlineData("afterrender-async-throw")]
-        [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/19666")]
         public async Task ComponentLifecycleMethodThrowsExceptionTerminatesTheCircuit(string id)
         {
             if (id == "setparameters-async-throw")
@@ -322,61 +372,74 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
 
             // Arrange
             var expectedError = "Unhandled exception in circuit .*";
-            var rootUri = ServerFixture.RootUri;
-            var baseUri = new Uri(rootUri, "/subdir");
-            await ConnectAutomaticallyAndWait(baseUri);
+            await using (var server = await StartServer<ServerStartup>(expectedErrorsFilter: (WriteContext val) => true))
+            {
+                ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new();
+                server.ServerLogged += (LogRecord record) => logs.Enqueue(record);
+                var rootUri = server.Url;
+                var baseUri = new Uri($"{rootUri}/subdir");
 
-            await Client.SelectAsync("test-selector-select", "BasicTestApp.ReliabilityComponent");
+                Assert.True(await Client.ConnectAsync(baseUri));
+                Assert.Single(Batches);
 
-            // Act
-            await Client.ExpectCircuitError(async () =>
-            {
-                await Client.ClickAsync(id, expectRenderBatch: false);
-            });
+                await Client.SelectAsync("test-selector-select", "BasicTestApp.ReliabilityComponent");
 
-            // Now if you try to click again, you will get *forcibly* disconnected for trying to talk to
-            // a circuit that's gone.
-            await Client.ExpectCircuitErrorAndDisconnect(async () =>
-            {
-                await Assert.ThrowsAsync<TaskCanceledException>(async () => await Client.ClickAsync(id, expectRenderBatch: false));
-            });
+                // Act
+                await Client.ExpectCircuitError(async () =>
+                {
+                    await Client.ClickAsync(id, expectRenderBatch: false);
+                });
 
-            // Checking logs at the end to avoid race condition.
-            Assert.Contains(
-                Logs,
-                e => LogLevel.Error == e.LogLevel && Regex.IsMatch(e.Message, expectedError));
+                // Now if you try to click again, you will get *forcibly* disconnected for trying to talk to
+                // a circuit that's gone.
+                await Client.ExpectCircuitErrorAndDisconnect(async () =>
+                {
+                    await Assert.ThrowsAsync<TaskCanceledException>(async () => await Client.ClickAsync(id, expectRenderBatch: false));
+                });
+
+                // Checking logs at the end to avoid race condition.
+                Assert.Contains(
+                    logs,
+                    e => LogLevel.Error == e.Write.LogLevel && Regex.IsMatch(e.Write.Message, expectedError));
+            }
         }
 
         [Fact]
-        [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/19666")]
         public async Task ComponentDisposeMethodThrowsExceptionTerminatesTheCircuit()
         {
             // Arrange
             var expectedError = "Unhandled exception in circuit .*";
-            var rootUri = ServerFixture.RootUri;
-            var baseUri = new Uri(rootUri, "/subdir");
-            await ConnectAutomaticallyAndWait(baseUri);
+            await using (var server = await StartServer<ServerStartup>(expectedErrorsFilter: (WriteContext val) => true))
+            {
+                ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new();
+                server.ServerLogged += (LogRecord record) => logs.Enqueue(record);
+                var rootUri = server.Url;
+                var baseUri = new Uri($"{rootUri}/subdir");
 
-            await Client.SelectAsync("test-selector-select", "BasicTestApp.ReliabilityComponent");
+                Assert.True(await Client.ConnectAsync(baseUri));
+                Assert.Single(Batches);
 
-            // Act - show then hide
-            await Client.ClickAsync("dispose-throw");
-            await Client.ExpectCircuitError(async () =>
-            {
-                await Client.ClickAsync("dispose-throw", expectRenderBatch: false);
-            });
+                await Client.SelectAsync("test-selector-select", "BasicTestApp.ReliabilityComponent");
 
-            // Now if you try to click again, you will get *forcibly* disconnected for trying to talk to
-            // a circuit that's gone.
-            await Client.ExpectCircuitErrorAndDisconnect(async () =>
-            {
-                await Assert.ThrowsAsync<TaskCanceledException>(async () => await Client.ClickAsync("dispose-throw", expectRenderBatch: false));
-            });
+                // Act - show then hide
+                await Client.ClickAsync("dispose-throw");
+                await Client.ExpectCircuitError(async () =>
+                {
+                    await Client.ClickAsync("dispose-throw", expectRenderBatch: false);
+                });
 
-            // Checking logs at the end to avoid race condition.
-            Assert.Contains(
-                Logs,
-                e => LogLevel.Error == e.LogLevel && Regex.IsMatch(e.Message, expectedError));
+                // Now if you try to click again, you will get *forcibly* disconnected for trying to talk to
+                // a circuit that's gone.
+                await Client.ExpectCircuitErrorAndDisconnect(async () =>
+                {
+                    await Assert.ThrowsAsync<TaskCanceledException>(async () => await Client.ClickAsync("dispose-throw", expectRenderBatch: false));
+                });
+
+                // Checking logs at the end to avoid race condition.
+                Assert.Contains(
+                    logs,
+                    e => LogLevel.Error == e.Write.LogLevel && Regex.IsMatch(e.Write.Message, expectedError));
+            }
         }
     }
 }
diff --git a/src/SignalR/common/testassets/Tests.Utils/FunctionalTestBase.cs b/src/Shared/SignalR/FunctionalTestBase.cs
similarity index 100%
rename from src/SignalR/common/testassets/Tests.Utils/FunctionalTestBase.cs
rename to src/Shared/SignalR/FunctionalTestBase.cs
diff --git a/src/SignalR/common/testassets/Tests.Utils/InProcessTestServer.cs b/src/Shared/SignalR/InProcessTestServer.cs
similarity index 100%
rename from src/SignalR/common/testassets/Tests.Utils/InProcessTestServer.cs
rename to src/Shared/SignalR/InProcessTestServer.cs
diff --git a/src/SignalR/common/testassets/Tests.Utils/LogRecord.cs b/src/Shared/SignalR/LogRecord.cs
similarity index 100%
rename from src/SignalR/common/testassets/Tests.Utils/LogRecord.cs
rename to src/Shared/SignalR/LogRecord.cs
diff --git a/src/SignalR/common/testassets/Tests.Utils/LogSinkProvider.cs b/src/Shared/SignalR/LogSinkProvider.cs
similarity index 100%
rename from src/SignalR/common/testassets/Tests.Utils/LogSinkProvider.cs
rename to src/Shared/SignalR/LogSinkProvider.cs
diff --git a/src/SignalR/common/testassets/Tests.Utils/VerifiableLoggedTest.cs b/src/Shared/SignalR/VerifiableLoggedTest.cs
similarity index 100%
rename from src/SignalR/common/testassets/Tests.Utils/VerifiableLoggedTest.cs
rename to src/Shared/SignalR/VerifiableLoggedTest.cs
diff --git a/src/SignalR/common/testassets/Tests.Utils/VerifyNoErrorsScope.cs b/src/Shared/SignalR/VerifyNoErrorScope.cs
similarity index 100%
rename from src/SignalR/common/testassets/Tests.Utils/VerifyNoErrorsScope.cs
rename to src/Shared/SignalR/VerifyNoErrorScope.cs
diff --git a/src/SignalR/common/testassets/Tests.Utils/WrappingLoggerFactory.cs b/src/Shared/SignalR/WrappingLoggerFactory.cs
similarity index 98%
rename from src/SignalR/common/testassets/Tests.Utils/WrappingLoggerFactory.cs
rename to src/Shared/SignalR/WrappingLoggerFactory.cs
index 05b6f79b30df445944177a4c445056520f826626..bf34b1a1a581830f731d17018b301a2251675d44 100644
--- a/src/SignalR/common/testassets/Tests.Utils/WrappingLoggerFactory.cs
+++ b/src/Shared/SignalR/WrappingLoggerFactory.cs
@@ -1,4 +1,4 @@
-// Copyright (c) .NET Foundation. All rights reserved.
+// Copyright (c) .NET Foundation. All rights reserved.
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
 using System;
diff --git a/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj b/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj
index dc4198b92409ba8a8b74d353c1384b88ac9a7ea4..80b109210370e5b934cd7eca423a0d081b4030c5 100644
--- a/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj
+++ b/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj
@@ -23,6 +23,7 @@
     <Reference Include="Microsoft.AspNetCore.SignalR.Common" />
 
     <Compile Include="$(SharedSourceRoot)ValueStopwatch\*.cs" />
+    <Compile Include="$(SharedSourceRoot)SignalR\*.cs" />
   </ItemGroup>
 
 </Project>