Ejemplo n.º 1
0
        public async Task ThrowsIfWeReceiveAnOutOfSequenceClientAcknowledge()
        {
            // Arrange
            var serviceProvider = new ServiceCollection().BuildServiceProvider();
            var firstBatchTCS   = new TaskCompletionSource <object>();
            var secondBatchTCS  = new TaskCompletionSource <object>();
            var offlineClient   = new CircuitClientProxy(new Mock <IClientProxy>(MockBehavior.Strict).Object, "offline-client");

            offlineClient.SetDisconnected();
            var            renderer       = GetRemoteRenderer(serviceProvider, offlineClient);
            RenderFragment initialContent = (builder) =>
            {
                builder.OpenElement(0, "my element");
                builder.AddContent(1, "some text");
                builder.CloseElement();
            };
            var trigger      = new Trigger();
            var renderIds    = new List <long>();
            var onlineClient = new Mock <IClientProxy>();

            onlineClient.Setup(c => c.SendCoreAsync(It.IsAny <string>(), It.IsAny <object[]>(), It.IsAny <CancellationToken>()))
            .Callback((string name, object[] value, CancellationToken token) => renderIds.Add((long)value[1]))
            .Returns <string, object[], CancellationToken>((n, v, t) => (long)v[1] == 2 ? firstBatchTCS.Task : secondBatchTCS.Task);

            // This produces the initial batch (id = 2)
            var result = await renderer.RenderComponentAsync <AutoParameterTestComponent>(
                ParameterCollection.FromDictionary(new Dictionary <string, object>
            {
                [nameof(AutoParameterTestComponent.Content)] = initialContent,
                [nameof(AutoParameterTestComponent.Trigger)] = trigger
            }));

            trigger.Component.Content = (builder) =>
            {
                builder.OpenElement(0, "offline element");
                builder.AddContent(1, "offline text");
                builder.CloseElement();
            };
            // This produces an additional batch (id = 3)
            trigger.TriggerRender();
            var originallyQueuedBatches = renderer.PendingRenderBatches.Count;

            // Act
            offlineClient.Transfer(onlineClient.Object, "new-connection");
            var task       = renderer.ProcessBufferedRenderBatches();
            var exceptions = new List <Exception>();

            renderer.UnhandledException += (sender, e) =>
            {
                exceptions.Add(e);
            };

            // Pretend that we missed the ack for the initial batch
            renderer.OnRenderCompleted(3, null);
            firstBatchTCS.SetResult(null);
            secondBatchTCS.SetResult(null);

            // Assert
            var exception = Assert.Single(exceptions);
        }
Ejemplo n.º 2
0
        public async Task ProcessBufferedRenderBatches_WritesRenders()
        {
            // Arrange
            var serviceProvider = new ServiceCollection().BuildServiceProvider();
            var renderIds       = new List <long>();

            var firstBatchTCS  = new TaskCompletionSource <object>();
            var secondBatchTCS = new TaskCompletionSource <object>();
            var thirdBatchTCS  = new TaskCompletionSource <object>();

            var initialClient = new Mock <IClientProxy>();

            initialClient.Setup(c => c.SendCoreAsync(It.IsAny <string>(), It.IsAny <object[]>(), It.IsAny <CancellationToken>()))
            .Callback((string name, object[] value, CancellationToken token) => renderIds.Add((long)value[1]))
            .Returns(firstBatchTCS.Task);
            var circuitClient = new CircuitClientProxy(initialClient.Object, "connection0");
            var renderer      = GetRemoteRenderer(serviceProvider, circuitClient);
            var component     = new TestComponent(builder =>
            {
                builder.OpenElement(0, "my element");
                builder.AddContent(1, "some text");
                builder.CloseElement();
            });

            var client = new Mock <IClientProxy>();

            client.Setup(c => c.SendCoreAsync(It.IsAny <string>(), It.IsAny <object[]>(), It.IsAny <CancellationToken>()))
            .Callback((string name, object[] value, CancellationToken token) => renderIds.Add((long)value[1]))
            .Returns <string, object[], CancellationToken>((n, v, t) => (long)v[1] == 3 ? secondBatchTCS.Task : thirdBatchTCS.Task);

            var componentId = renderer.AssignRootComponentId(component);

            component.TriggerRender();
            renderer.OnRenderCompleted(2, null);
            firstBatchTCS.SetResult(null);

            circuitClient.SetDisconnected();
            component.TriggerRender();
            component.TriggerRender();

            // Act
            circuitClient.Transfer(client.Object, "new-connection");
            var task = renderer.ProcessBufferedRenderBatches();

            foreach (var id in renderIds.ToArray())
            {
                renderer.OnRenderCompleted(id, null);
            }

            secondBatchTCS.SetResult(null);
            thirdBatchTCS.SetResult(null);

            // Assert
            Assert.Equal(new long[] { 2, 3, 4 }, renderIds);
            Assert.True(task.Wait(3000), "One or more render batches werent acknowledged");

            await task;
        }
Ejemplo n.º 3
0
 private TestRemoteRenderer GetRemoteRenderer(IServiceProvider serviceProvider, CircuitClientProxy circuitClient = null)
 {
     return(new TestRemoteRenderer(
                serviceProvider,
                NullLoggerFactory.Instance,
                new CircuitOptions(),
                circuitClient ?? new CircuitClientProxy(),
                NullLogger.Instance));
 }
 private RemoteRenderer GetRemoteRenderer(IServiceProvider serviceProvider, CircuitClientProxy circuitClientProxy)
 {
     return(new RemoteRenderer(
                serviceProvider,
                new RendererRegistry(),
                Mock.Of <IJSRuntime>(),
                circuitClientProxy,
                Dispatcher,
                HtmlEncoder.Default,
                NullLogger.Instance));
 }
        public async Task ProcessBufferedRenderBatches_WritesRenders()
        {
            // Arrange
            var serviceProvider = new ServiceCollection().BuildServiceProvider();
            var renderIds       = new List <int>();

            var initialClient = new Mock <IClientProxy>();

            initialClient.Setup(c => c.SendCoreAsync(It.IsAny <string>(), It.IsAny <object[]>(), It.IsAny <CancellationToken>()))
            .Callback((string name, object[] value, CancellationToken token) =>
            {
                renderIds.Add((int)value[1]);
            })
            .Returns(Task.CompletedTask);
            var circuitClient = new CircuitClientProxy(initialClient.Object, "connection0");
            var renderer      = GetRemoteRenderer(serviceProvider, circuitClient);
            var component     = new TestComponent(builder =>
            {
                builder.OpenElement(0, "my element");
                builder.AddContent(1, "some text");
                builder.CloseElement();
            });


            var client = new Mock <IClientProxy>();

            client.Setup(c => c.SendCoreAsync(It.IsAny <string>(), It.IsAny <object[]>(), It.IsAny <CancellationToken>()))
            .Callback((string name, object[] value, CancellationToken token) =>
            {
                renderIds.Add((int)value[1]);
            })
            .Returns(Task.CompletedTask);
            var componentId = renderer.AssignRootComponentId(component);

            component.TriggerRender();
            renderer.OnRenderCompleted(1, null);

            circuitClient.SetDisconnected();
            component.TriggerRender();
            component.TriggerRender();

            // Act
            circuitClient.Transfer(client.Object, "new-connection");
            var task = renderer.ProcessBufferedRenderBatches();

            foreach (var id in renderIds)
            {
                renderer.OnRenderCompleted(id, null);
            }
            await task;

            // Assert
            client.Verify(c => c.SendCoreAsync("JS.RenderBatch", It.IsAny <object[]>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
        }
Ejemplo n.º 6
0
        // Implement a `CreateCircuitHostAsync` that mocks the construction
        // of the CircuitHost.
        public ValueTask <CircuitHost> CreateCircuitHostAsync(
            IReadOnlyList <ComponentDescriptor> components,
            CircuitClientProxy client,
            string baseUri,
            string uri,
            ClaimsPrincipal user,
            IPersistentComponentStateStore store)
        {
            var serviceScope = new Mock <IServiceScope>();
            var circuitHost  = TestCircuitHost.Create(serviceScope: new AsyncServiceScope(serviceScope.Object));

            return(ValueTask.FromResult(circuitHost));
        }
Ejemplo n.º 7
0
 /// <summary>
 /// Creates a new <see cref="RemoteRenderer"/>.
 /// </summary>
 public RemoteRenderer(
     IServiceProvider serviceProvider,
     ILoggerFactory loggerFactory,
     CircuitOptions options,
     IJSRuntime jsRuntime,
     CircuitClientProxy client,
     ILogger logger)
     : base(serviceProvider, loggerFactory)
 {
     _jsRuntime = jsRuntime;
     _client    = client;
     _options   = options;
     _logger    = logger;
 }
Ejemplo n.º 8
0
            public override CircuitHost CreateCircuitHost(HttpContext httpContext, CircuitClientProxy client, string uriAbsolute, string baseUriAbsolute)
            {
                var serviceCollection = new ServiceCollection();

                serviceCollection.AddScoped <IUriHelper>(_ =>
                {
                    var uriHelper = new RemoteUriHelper(NullLogger <RemoteUriHelper> .Instance);
                    uriHelper.InitializeState(uriAbsolute, baseUriAbsolute);
                    return(uriHelper);
                });
                var serviceScope = serviceCollection.BuildServiceProvider().CreateScope();

                return(TestCircuitHost.Create(serviceScope));
            }
Ejemplo n.º 9
0
    public void Transfer_SetsConnected()
    {
        // Arrange
        var clientProxy = Mock.Of <IClientProxy>(
            c => c.SendCoreAsync(It.IsAny <string>(), It.IsAny <object[]>(), It.IsAny <CancellationToken>()) == Task.CompletedTask);
        var circuitClient = new CircuitClientProxy(clientProxy, "connection0");

        circuitClient.SetDisconnected();

        // Act
        circuitClient.Transfer(Mock.Of <IClientProxy>(), "connection1");

        // Assert
        Assert.True(circuitClient.Connected);
    }
Ejemplo n.º 10
0
        public void IfInitialized_IsConnectedValueDeterminedByCircuitProxy()
        {
            // Arrange
            var clientProxy            = new FakeClientProxy();
            var circuitProxy           = new CircuitClientProxy(clientProxy, "test connection");
            var remoteComponentContext = new RemoteComponentContext();

            // Act/Assert: Can observe connected state
            remoteComponentContext.Initialize(circuitProxy);
            Assert.True(remoteComponentContext.IsConnected);

            // Act/Assert: Can observe disconnected state
            circuitProxy.SetDisconnected();
            Assert.False(remoteComponentContext.IsConnected);
        }
Ejemplo n.º 11
0
    /// <summary>
    /// Creates a new <see cref="RemoteRenderer"/>.
    /// </summary>
    public RemoteRenderer(
        IServiceProvider serviceProvider,
        ILoggerFactory loggerFactory,
        CircuitOptions options,
        CircuitClientProxy client,
        ILogger logger,
        RemoteJSRuntime jsRuntime,
        CircuitJSComponentInterop jsComponentInterop)
        : base(serviceProvider, loggerFactory, jsRuntime.ReadJsonSerializerOptions(), jsComponentInterop)
    {
        _client  = client;
        _options = options;
        _logger  = logger;

        ElementReferenceContext = jsRuntime.ElementReferenceContext;
    }
Ejemplo n.º 12
0
        /// <summary>
        /// Creates a new <see cref="RemoteRenderer"/>.
        /// </summary>
        public RemoteRenderer(
            IServiceProvider serviceProvider,
            RendererRegistry rendererRegistry,
            IJSRuntime jsRuntime,
            CircuitClientProxy client,
            IDispatcher dispatcher,
            HtmlEncoder encoder,
            ILogger logger)
            : base(serviceProvider, encoder.Encode, dispatcher)
        {
            _rendererRegistry = rendererRegistry;
            _jsRuntime        = jsRuntime;
            _client           = client;

            _id     = _rendererRegistry.Add(this);
            _logger = logger;
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Creates a new <see cref="RemoteRenderer"/>.
        /// </summary>
        public RemoteRenderer(
            IServiceProvider serviceProvider,
            ILoggerFactory loggerFactory,
            RendererRegistry rendererRegistry,
            IJSRuntime jsRuntime,
            CircuitClientProxy client,
            HtmlEncoder encoder,
            ILogger logger)
            : base(serviceProvider, loggerFactory, encoder.Encode)
        {
            _rendererRegistry = rendererRegistry;
            _jsRuntime        = jsRuntime;
            _client           = client;

            Id      = _rendererRegistry.Add(this);
            _logger = logger;
        }
Ejemplo n.º 14
0
    public CircuitHost(
        CircuitId circuitId,
        AsyncServiceScope scope,
        CircuitOptions options,
        CircuitClientProxy client,
        RemoteRenderer renderer,
        IReadOnlyList <ComponentDescriptor> descriptors,
        RemoteJSRuntime jsRuntime,
        RemoteNavigationManager navigationManager,
        CircuitHandler[] circuitHandlers,
        ILogger logger)
    {
        CircuitId = circuitId;
        if (CircuitId.Secret is null)
        {
            // Prevent the use of a 'default' secret.
            throw new ArgumentException($"Property '{nameof(CircuitId.Secret)}' cannot be null.", nameof(circuitId));
        }

        _scope             = scope;
        _options           = options ?? throw new ArgumentNullException(nameof(options));
        Client             = client ?? throw new ArgumentNullException(nameof(client));
        Renderer           = renderer ?? throw new ArgumentNullException(nameof(renderer));
        Descriptors        = descriptors ?? throw new ArgumentNullException(nameof(descriptors));
        JSRuntime          = jsRuntime ?? throw new ArgumentNullException(nameof(jsRuntime));
        _navigationManager = navigationManager ?? throw new ArgumentNullException(nameof(navigationManager));
        _circuitHandlers   = circuitHandlers ?? throw new ArgumentNullException(nameof(circuitHandlers));
        _logger            = logger ?? throw new ArgumentNullException(nameof(logger));

        Services = scope.ServiceProvider;

        Circuit = new Circuit(this);
        Handle  = new CircuitHandle()
        {
            CircuitHost = this,
        };

        // An unhandled exception from the renderer is always fatal because it came from user code.
        Renderer.UnhandledException += ReportAndInvoke_UnhandledException;
        Renderer.UnhandledSynchronizationException += SynchronizationContext_UnhandledException;

        JSRuntime.UnhandledException += ReportAndInvoke_UnhandledException;

        _navigationManager.UnhandledException += ReportAndInvoke_UnhandledException;
    }
Ejemplo n.º 15
0
    public static CircuitHost Create(
        CircuitId?circuitId            = null,
        AsyncServiceScope?serviceScope = null,
        RemoteRenderer remoteRenderer  = null,
        IReadOnlyList <ComponentDescriptor> descriptors = null,
        CircuitHandler[] handlers      = null,
        CircuitClientProxy clientProxy = null)
    {
        serviceScope = serviceScope ?? new AsyncServiceScope(Mock.Of <IServiceScope>());
        clientProxy  = clientProxy ?? new CircuitClientProxy(Mock.Of <IClientProxy>(), Guid.NewGuid().ToString());
        var jsRuntime         = new RemoteJSRuntime(Options.Create(new CircuitOptions()), Options.Create(new HubOptions <ComponentHub>()), Mock.Of <ILogger <RemoteJSRuntime> >());
        var navigationManager = new RemoteNavigationManager(Mock.Of <ILogger <RemoteNavigationManager> >());
        var serviceProvider   = new Mock <IServiceProvider>();

        serviceProvider
        .Setup(services => services.GetService(typeof(IJSRuntime)))
        .Returns(jsRuntime);

        if (remoteRenderer == null)
        {
            remoteRenderer = new RemoteRenderer(
                serviceProvider.Object,
                NullLoggerFactory.Instance,
                new CircuitOptions(),
                clientProxy,
                NullLogger.Instance,
                jsRuntime,
                new CircuitJSComponentInterop(new CircuitOptions()));
        }

        handlers ??= Array.Empty <CircuitHandler>();
        return(new TestCircuitHost(
                   circuitId is null ? new CircuitId(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()) : circuitId.Value,
                   serviceScope.Value,
                   new CircuitOptions(),
                   clientProxy,
                   remoteRenderer,
                   descriptors ?? new List <ComponentDescriptor>(),
                   jsRuntime,
                   navigationManager,
                   handlers,
                   NullLogger <CircuitHost> .Instance));
    }
Ejemplo n.º 16
0
        private RemoteRenderer GetRemoteRenderer(IServiceProvider serviceProvider, CircuitClientProxy circuitClientProxy)
        {
            var jsRuntime = new Mock <IJSRuntime>();

            jsRuntime.Setup(r => r.InvokeAsync <object>(
                                "Blazor._internal.attachRootComponentToElement",
                                It.IsAny <int>(),
                                It.IsAny <string>(),
                                It.IsAny <int>()))
            .ReturnsAsync(Task.FromResult <object>(null));

            return(new RemoteRenderer(
                       serviceProvider,
                       new RendererRegistry(),
                       jsRuntime.Object,
                       circuitClientProxy,
                       Dispatcher,
                       HtmlEncoder.Default,
                       NullLogger.Instance));
        }
Ejemplo n.º 17
0
    public async Task SendCoreAsync_WithoutTransfer()
    {
        // Arrange
        bool?isCancelled = null;
        var  clientProxy = new Mock <IClientProxy>();

        clientProxy.Setup(c => c.SendCoreAsync(It.IsAny <string>(), It.IsAny <object[]>(), It.IsAny <CancellationToken>()))
        .Callback((string _, object[] __, CancellationToken token) =>
        {
            isCancelled = token.IsCancellationRequested;
        })
        .Returns(Task.CompletedTask);
        var circuitClient = new CircuitClientProxy(clientProxy.Object, "connection0");

        // Act
        var   sendTask = circuitClient.SendCoreAsync("test", Array.Empty <object>());
        await sendTask;

        // Assert
        Assert.False(isCancelled);
    }
Ejemplo n.º 18
0
 public TestRemoteRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory, CircuitOptions options, CircuitClientProxy client, ILogger logger)
     : base(serviceProvider, loggerFactory, options, client, logger, null)
 {
 }
Ejemplo n.º 19
0
 private TestCircuitHost(CircuitId circuitId, AsyncServiceScope scope, CircuitOptions options, CircuitClientProxy client, RemoteRenderer renderer, IReadOnlyList <ComponentDescriptor> descriptors, RemoteJSRuntime jsRuntime, RemoteNavigationManager navigationManager, CircuitHandler[] circuitHandlers, ILogger logger)
     : base(circuitId, scope, options, client, renderer, descriptors, jsRuntime, navigationManager, circuitHandlers, logger)
 {
 }
Ejemplo n.º 20
0
    public async ValueTask <CircuitHost> CreateCircuitHostAsync(
        IReadOnlyList <ComponentDescriptor> components,
        CircuitClientProxy client,
        string baseUri,
        string uri,
        ClaimsPrincipal user,
        IPersistentComponentStateStore store)
    {
        var scope     = _scopeFactory.CreateAsyncScope();
        var jsRuntime = (RemoteJSRuntime)scope.ServiceProvider.GetRequiredService <IJSRuntime>();

        jsRuntime.Initialize(client);

        var navigationManager      = (RemoteNavigationManager)scope.ServiceProvider.GetRequiredService <NavigationManager>();
        var navigationInterception = (RemoteNavigationInterception)scope.ServiceProvider.GetRequiredService <INavigationInterception>();

        if (client.Connected)
        {
            navigationManager.AttachJsRuntime(jsRuntime);
            navigationManager.Initialize(baseUri, uri);

            navigationInterception.AttachJSRuntime(jsRuntime);
        }
        else
        {
            navigationManager.Initialize(baseUri, uri);
        }

        var appLifetime = scope.ServiceProvider.GetRequiredService <ComponentStatePersistenceManager>();
        await appLifetime.RestoreStateAsync(store);

        var jsComponentInterop = new CircuitJSComponentInterop(_options);
        var renderer           = new RemoteRenderer(
            scope.ServiceProvider,
            _loggerFactory,
            _options,
            client,
            _loggerFactory.CreateLogger <RemoteRenderer>(),
            jsRuntime,
            jsComponentInterop);

        var circuitHandlers = scope.ServiceProvider.GetServices <CircuitHandler>()
                              .OrderBy(h => h.Order)
                              .ToArray();

        var circuitHost = new CircuitHost(
            _circuitIdFactory.CreateCircuitId(),
            scope,
            _options,
            client,
            renderer,
            components,
            jsRuntime,
            navigationManager,
            circuitHandlers,
            _loggerFactory.CreateLogger <CircuitHost>());

        Log.CreatedCircuit(_logger, circuitHost);

        // Initialize per - circuit data that services need
        (circuitHost.Services.GetRequiredService <ICircuitAccessor>() as DefaultCircuitAccessor).Circuit = circuitHost.Circuit;
        circuitHost.SetCircuitUser(user);

        return(circuitHost);
    }
Ejemplo n.º 21
0
 public TestRemoteRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory, CircuitOptions options, IJSRuntime jsRuntime, CircuitClientProxy client, ILogger logger)
     : base(serviceProvider, loggerFactory, options, jsRuntime, client, logger)
 {
 }
Ejemplo n.º 22
0
        public async ValueTask <string> StartCircuit(string baseUri, string uri)
        {
            var circuitHost = GetCircuit();

            if (circuitHost != null)
            {
                // This is an error condition and an attempt to bind multiple circuits to a single connection.
                // We can reject this and terminate the connection.
                Log.CircuitAlreadyInitialized(_logger, circuitHost.CircuitId);
                await NotifyClientError(Clients.Caller, $"The circuit host '{circuitHost.CircuitId}' has already been initialized.");

                Context.Abort();
                return(null);
            }

            if (baseUri == null ||
                uri == null ||
                !Uri.IsWellFormedUriString(baseUri, UriKind.Absolute) ||
                !Uri.IsWellFormedUriString(uri, UriKind.Absolute))
            {
                // We do some really minimal validation here to prevent obviously wrong data from getting in
                // without duplicating too much logic.
                //
                // This is an error condition attempting to initialize the circuit in a way that would fail.
                // We can reject this and terminate the connection.
                Log.InvalidInputData(_logger);
                await NotifyClientError(Clients.Caller, $"The uris provided are invalid.");

                Context.Abort();
                return(null);
            }

            // From this point, we can try to actually initialize the circuit.
            if (DefaultCircuitFactory.ResolveComponentMetadata(Context.GetHttpContext()).Count == 0)
            {
                // No components preregistered so return. This is totally normal if the components were prerendered.
                Log.NoComponentsRegisteredInEndpoint(_logger, Context.GetHttpContext().GetEndpoint()?.DisplayName);
                return(null);
            }

            try
            {
                var circuitClient = new CircuitClientProxy(Clients.Caller, Context.ConnectionId);
                circuitHost = _circuitFactory.CreateCircuitHost(
                    Context.GetHttpContext(),
                    circuitClient,
                    baseUri,
                    uri,
                    Context.User);

                // Fire-and-forget the initialization process, because we can't block the
                // SignalR message loop (we'd get a deadlock if any of the initialization
                // logic relied on receiving a subsequent message from SignalR), and it will
                // take care of its own errors anyway.
                _ = circuitHost.InitializeAsync(Context.ConnectionAborted);

                // 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);
                return(circuitHost.CircuitId);
            }
            catch (Exception ex)
            {
                // If the circuit fails to initialize synchronously we can notify the client immediately
                // and shut down the connection.
                Log.CircuitInitializationFailed(_logger, ex);
                await NotifyClientError(Clients.Caller, "The circuit failed to initialize.");

                Context.Abort();
                return(null);
            }
        }
Ejemplo n.º 23
0
 public TestRemoteRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory, CircuitOptions options, CircuitClientProxy client, ILogger logger)
     : base(serviceProvider, loggerFactory, options, client, logger, CreateJSRuntime(options), new CircuitJSComponentInterop(options))
 {
 }
        public async ValueTask <string> StartCircuit(string baseUri, string uri, string serializedComponentRecords)
        {
            var circuitHost = GetCircuit();

            if (circuitHost != null)
            {
                // This is an error condition and an attempt to bind multiple circuits to a single connection.
                // We can reject this and terminate the connection.
                Log.CircuitAlreadyInitialized(_logger, circuitHost.CircuitId);
                await NotifyClientError(Clients.Caller, $"The circuit host '{circuitHost.CircuitId}' has already been initialized.");

                Context.Abort();
                return(null);
            }

            if (baseUri == null ||
                uri == null ||
                !Uri.IsWellFormedUriString(baseUri, UriKind.Absolute) ||
                !Uri.IsWellFormedUriString(uri, UriKind.Absolute))
            {
                // We do some really minimal validation here to prevent obviously wrong data from getting in
                // without duplicating too much logic.
                //
                // This is an error condition attempting to initialize the circuit in a way that would fail.
                // We can reject this and terminate the connection.
                Log.InvalidInputData(_logger);
                await NotifyClientError(Clients.Caller, $"The uris provided are invalid.");

                Context.Abort();
                return(null);
            }

            if (!_serverComponentSerializer.TryDeserializeComponentDescriptorCollection(serializedComponentRecords, out var components))
            {
                Log.InvalidInputData(_logger);
                await NotifyClientError(Clients.Caller, $"The list of component records is not valid.");

                Context.Abort();
                return(null);
            }

            try
            {
                var circuitClient = new CircuitClientProxy(Clients.Caller, Context.ConnectionId);
                circuitHost = _circuitFactory.CreateCircuitHost(
                    components,
                    circuitClient,
                    baseUri,
                    uri,
                    Context.User);

                // Fire-and-forget the initialization process, because we can't block the
                // SignalR message loop (we'd get a deadlock if any of the initialization
                // logic relied on receiving a subsequent message from SignalR), and it will
                // take care of its own errors anyway.
                _ = circuitHost.InitializeAsync(Context.ConnectionAborted);

                // 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);

                // Returning the secret here so the client can reconnect.
                //
                // Logging the secret and circuit ID here so we can associate them with just logs (if TRACE level is on).
                Log.CreatedCircuit(_logger, circuitHost.CircuitId, circuitHost.CircuitId.Secret, Context.ConnectionId);
                return(circuitHost.CircuitId.Secret);
            }
            catch (Exception ex)
            {
                // If the circuit fails to initialize synchronously we can notify the client immediately
                // and shut down the connection.
                Log.CircuitInitializationFailed(_logger, ex);
                await NotifyClientError(Clients.Caller, "The circuit failed to initialize.");

                Context.Abort();
                return(null);
            }
        }
Ejemplo n.º 25
0
        private TestRemoteRenderer GetRemoteRenderer(IServiceProvider serviceProvider, CircuitClientProxy circuitClient = null)
        {
            var jsRuntime = new Mock <IJSRuntime>();

            jsRuntime.Setup(r => r.InvokeAsync <object>(
                                "Blazor._internal.attachRootComponentToElement",
                                It.IsAny <int>(),
                                It.IsAny <string>(),
                                It.IsAny <int>()))
            .ReturnsAsync(Task.FromResult <object>(null));

            return(new TestRemoteRenderer(
                       serviceProvider,
                       NullLoggerFactory.Instance,
                       new CircuitOptions(),
                       jsRuntime.Object,
                       circuitClient ?? new CircuitClientProxy(),
                       NullLogger.Instance));
        }
Ejemplo n.º 26
0
 public override CircuitHost CreateCircuitHost(HttpContext httpContext, CircuitClientProxy client, string uriAbsolute, string baseUriAbsolute)
 {
     return(TestCircuitHost.Create(Guid.NewGuid().ToString(), MockServiceScope.Object));
 }