-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Move ComponentHubReliability tests to unit and E2E tests #32834
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4f9db85
3739a4e
4b0ca5b
d1bc83b
838d857
269191f
6def910
8df069d
7f6ae32
783a892
013a4ac
cdc4733
34d08f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| // 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; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Security.Claims; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.AspNetCore.Components.Lifetime; | ||
| using Microsoft.AspNetCore.Components.Routing; | ||
| using Microsoft.AspNetCore.DataProtection; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Logging; | ||
| using Microsoft.Extensions.Options; | ||
| using Microsoft.JSInterop; | ||
|
|
||
| namespace Microsoft.AspNetCore.Components.Server.Circuits | ||
| { | ||
| internal sealed class CircuitHandleRegistry : ICircuitHandleRegistry | ||
| { | ||
| public CircuitHandle GetCircuitHandle(IDictionary<object, object?>circuitHandles, object circuitKey) | ||
| { | ||
| if (circuitHandles.TryGetValue(circuitKey, out var circuitHandle)) | ||
| { | ||
| return (CircuitHandle) circuitHandle; | ||
| } | ||
|
|
||
| return null;; | ||
captainsafia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| public CircuitHost GetCircuit(IDictionary<object, object?> circuitHandles, object circuitKey) | ||
| { | ||
| if (circuitHandles.TryGetValue(circuitKey, out var circuitHandle)) | ||
| { | ||
| return ((CircuitHandle)circuitHandle).CircuitHost; | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| public void SetCircuit(IDictionary<object, object?> circuitHandles, object circuitKey, CircuitHost circuitHost) | ||
| { | ||
| circuitHandles[circuitKey] = circuitHost?.Handle; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // 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; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Security.Claims; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.AspNetCore.Components.Lifetime; | ||
| using Microsoft.AspNetCore.Components.Routing; | ||
| using Microsoft.AspNetCore.DataProtection; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Logging; | ||
| using Microsoft.Extensions.Options; | ||
| using Microsoft.JSInterop; | ||
|
|
||
| namespace Microsoft.AspNetCore.Components.Server.Circuits | ||
| { | ||
| internal interface ICircuitFactory | ||
| { | ||
| ValueTask<CircuitHost> CreateCircuitHostAsync( | ||
| IReadOnlyList<ComponentDescriptor> components, | ||
| CircuitClientProxy client, | ||
| string baseUri, | ||
| string uri, | ||
| ClaimsPrincipal user, | ||
| IComponentApplicationStateStore store); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // 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; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Security.Claims; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.AspNetCore.Components.Lifetime; | ||
| using Microsoft.AspNetCore.Components.Routing; | ||
| using Microsoft.AspNetCore.DataProtection; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Logging; | ||
| using Microsoft.Extensions.Options; | ||
| using Microsoft.JSInterop; | ||
|
|
||
| namespace Microsoft.AspNetCore.Components.Server.Circuits | ||
| { | ||
| internal interface ICircuitHandleRegistry | ||
| { | ||
| CircuitHandle GetCircuitHandle(IDictionary<object, object?> circuitHandles, object circuitKey); | ||
|
|
||
| CircuitHost GetCircuit(IDictionary<object, object?> circuitHandles, object circuitKey); | ||
|
|
||
| void SetCircuit(IDictionary<object, object?> circuitHandles, object circuitKey, CircuitHost circuitHost); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // 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; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Security.Claims; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.AspNetCore.Components.Lifetime; | ||
| using Microsoft.AspNetCore.Components.Routing; | ||
| using Microsoft.AspNetCore.DataProtection; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Logging; | ||
| using Microsoft.Extensions.Options; | ||
| using Microsoft.JSInterop; | ||
|
|
||
| namespace Microsoft.AspNetCore.Components.Server | ||
| { | ||
| internal interface IServerComponentDeserializer | ||
| { | ||
| bool TryDeserializeComponentDescriptorCollection( | ||
| string serializedComponentRecords, | ||
| out List<ComponentDescriptor> descriptors); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,26 +37,29 @@ namespace Microsoft.AspNetCore.Components.Server | |
| internal sealed class ComponentHub : Hub | ||
| { | ||
| private static readonly object CircuitKey = new object(); | ||
| private readonly ServerComponentDeserializer _serverComponentSerializer; | ||
| private readonly IServerComponentDeserializer _serverComponentSerializer; | ||
| private readonly IDataProtectionProvider _dataProtectionProvider; | ||
| private readonly CircuitFactory _circuitFactory; | ||
| private readonly ICircuitFactory _circuitFactory; | ||
| private readonly CircuitIdFactory _circuitIdFactory; | ||
| private readonly CircuitRegistry _circuitRegistry; | ||
| private readonly ICircuitHandleRegistry _circuitHandleRegistry; | ||
| private readonly ILogger _logger; | ||
|
|
||
| public ComponentHub( | ||
| ServerComponentDeserializer serializer, | ||
| IServerComponentDeserializer serializer, | ||
| IDataProtectionProvider dataProtectionProvider, | ||
| CircuitFactory circuitFactory, | ||
| ICircuitFactory circuitFactory, | ||
| CircuitIdFactory circuitIdFactory, | ||
| CircuitRegistry circuitRegistry, | ||
| ICircuitHandleRegistry circuitHandleRegistry, | ||
| ILogger<ComponentHub> logger) | ||
| { | ||
| _serverComponentSerializer = serializer; | ||
| _dataProtectionProvider = dataProtectionProvider; | ||
| _circuitFactory = circuitFactory; | ||
| _circuitIdFactory = circuitIdFactory; | ||
| _circuitRegistry = circuitRegistry; | ||
| _circuitHandleRegistry = circuitHandleRegistry; | ||
| _logger = logger; | ||
| } | ||
|
|
||
|
|
@@ -69,7 +72,7 @@ public override Task OnDisconnectedAsync(Exception exception) | |
| { | ||
| // If the CircuitHost is gone now this isn't an error. This could happen if the disconnect | ||
| // if the result of well behaving client hanging up after an unhandled exception. | ||
| var circuitHost = GetCircuit(); | ||
| var circuitHost = _circuitHandleRegistry.GetCircuit(Context.Items, CircuitKey); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't we configure Context.Items instead of introducing the registry?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The original intent here was to have an injected type that we could mock in the tests to avoid actually have to created a circuit instance. This originally started out as a singleton service with its own internal dictionary. However, that doesn't work because It's not possible for us to configure |
||
| if (circuitHost == null) | ||
| { | ||
| return Task.CompletedTask; | ||
|
|
@@ -80,7 +83,7 @@ public override Task OnDisconnectedAsync(Exception exception) | |
|
|
||
| public async ValueTask<string> StartCircuit(string baseUri, string uri, string serializedComponentRecords, string applicationState) | ||
| { | ||
| var circuitHost = GetCircuit(); | ||
| var circuitHost = _circuitHandleRegistry.GetCircuit(Context.Items, CircuitKey); | ||
| if (circuitHost != null) | ||
| { | ||
| // This is an error condition and an attempt to bind multiple circuits to a single connection. | ||
|
|
@@ -139,7 +142,7 @@ public async ValueTask<string> StartCircuit(string baseUri, string uri, string s | |
| // It's safe to *publish* the circuit now because nothing will be able | ||
| // to run inside it until after InitializeAsync completes. | ||
| _circuitRegistry.Register(circuitHost); | ||
| SetCircuit(circuitHost); | ||
| _circuitHandleRegistry.SetCircuit(Context.Items, CircuitKey, circuitHost); | ||
|
|
||
| // Returning the secret here so the client can reconnect. | ||
| // | ||
|
|
@@ -176,7 +179,7 @@ public async ValueTask<bool> ConnectCircuit(string circuitIdSecret) | |
| Context.ConnectionAborted); | ||
| if (circuitHost != null) | ||
| { | ||
| SetCircuit(circuitHost); | ||
| _circuitHandleRegistry.SetCircuit(Context.Items, CircuitKey, circuitHost); | ||
| circuitHost.SetCircuitUser(Context.User); | ||
| circuitHost.SendPendingBatches(); | ||
| return true; | ||
|
|
@@ -251,7 +254,7 @@ public async ValueTask OnLocationChanged(string uri, bool intercepted) | |
| // See comment on error handling on the class definition. | ||
| private async ValueTask<CircuitHost> GetActiveCircuitAsync([CallerMemberName] string callSite = "") | ||
| { | ||
| var handle = (CircuitHandle)Context.Items[CircuitKey]; | ||
| var handle = _circuitHandleRegistry.GetCircuitHandle(Context.Items, CircuitKey); | ||
| var circuitHost = handle?.CircuitHost; | ||
| if (handle != null && circuitHost == null) | ||
| { | ||
|
|
@@ -275,16 +278,6 @@ private async ValueTask<CircuitHost> GetActiveCircuitAsync([CallerMemberName] st | |
| return circuitHost; | ||
| } | ||
|
|
||
| private CircuitHost GetCircuit() | ||
| { | ||
| return ((CircuitHandle)Context.Items[CircuitKey])?.CircuitHost; | ||
| } | ||
|
|
||
| private void SetCircuit(CircuitHost circuitHost) | ||
| { | ||
| Context.Items[CircuitKey] = circuitHost?.Handle; | ||
| } | ||
|
|
||
| private static Task NotifyClientError(IClientProxy client, string error) => client.SendAsync("JS.Error", error); | ||
|
|
||
| private static class Log | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.