예제 #1
0
    // InitializeAsync is used in a fire-and-forget context, so it's responsible for its own
    // error handling.
    public Task InitializeAsync(ProtectedPrerenderComponentApplicationStore store, CancellationToken cancellationToken)
    {
        Log.InitializationStarted(_logger);

        return(Renderer.Dispatcher.InvokeAsync(async() =>
        {
            if (_initialized)
            {
                throw new InvalidOperationException("The circuit host is already initialized.");
            }

            try
            {
                _initialized = true; // We're ready to accept incoming JSInterop calls from here on

                await OnCircuitOpenedAsync(cancellationToken);
                await OnConnectionUpAsync(cancellationToken);

                // Here, we add each root component but don't await the returned tasks so that the
                // components can be processed in parallel.
                var count = Descriptors.Count;
                var pendingRenders = new Task[count];
                for (var i = 0; i < count; i++)
                {
                    var(componentType, parameters, sequence) = Descriptors[i];
                    pendingRenders[i] = Renderer.AddComponentAsync(componentType, parameters, sequence.ToString(CultureInfo.InvariantCulture));
                }

                // Now we wait for all components to finish rendering.
                await Task.WhenAll(pendingRenders);

                // At this point all components have successfully produced an initial render and we can clear the contents of the component
                // application state store. This ensures the memory that was not used during the initial render of these components gets
                // reclaimed since no-one else is holding on to it any longer.
                store.ExistingState.Clear();

                Log.InitializationSucceeded(_logger);
            }
            catch (Exception ex)
            {
                // Report errors asynchronously. InitializeAsync is designed not to throw.
                Log.InitializationFailed(_logger, ex);
                UnhandledException?.Invoke(this, new UnhandledExceptionEventArgs(ex, isTerminating: false));
                await TryNotifyClientErrorAsync(Client, GetClientErrorMessage(ex), ex);
            }
        }));
    }
예제 #2
0
        public async Task GetPersistStateAsync_CanUnprotectPersistedState()
        {
            // Arrange
            var expectedState = new Dictionary <string, byte[]>()
            {
                ["MyValue"] = new byte[] { 1, 2, 3, 4 }
            };

            var persistedState = Convert.ToBase64String(_protector.Protect(JsonSerializer.SerializeToUtf8Bytes(expectedState)));
            var store          = new ProtectedPrerenderComponentApplicationStore(persistedState, _provider);

            // Act
            var restored = await store.GetPersistedStateAsync();

            // Assert
            Assert.Equal(expectedState, restored);
        }
예제 #3
0
        public async Task PersistStateAsync_ProtectsPersistedState()
        {
            // Arrange
            var expected = @"{""MyValue"":""AQIDBA==""}";
            var store    = new ProtectedPrerenderComponentApplicationStore(_provider);

            var state = new Dictionary <string, byte[]>()
            {
                ["MyValue"] = new byte[] { 1, 2, 3, 4 }
            };

            // Act
            await store.PersistStateAsync(state);

            // Assert
            Assert.Equal(expected, _protector.Unprotect(store.PersistedState));
        }
예제 #4
0
        // InitializeAsync is used in a fire-and-forget context, so it's responsible for its own
        // error handling.
        public Task InitializeAsync(ProtectedPrerenderComponentApplicationStore store, CancellationToken cancellationToken)
        {
            Log.InitializationStarted(_logger);

            return(Renderer.Dispatcher.InvokeAsync(async() =>
            {
                if (_initialized)
                {
                    throw new InvalidOperationException("The circuit host is already initialized.");
                }

                try
                {
                    _initialized = true; // We're ready to accept incoming JSInterop calls from here on

                    await OnCircuitOpenedAsync(cancellationToken);
                    await OnConnectionUpAsync(cancellationToken);

                    // We add the root components *after* the circuit is flagged as open.
                    // That's because AddComponentAsync waits for quiescence, which can take
                    // arbitrarily long. In the meantime we might need to be receiving and
                    // processing incoming JSInterop calls or similar.
                    var count = Descriptors.Count;
                    for (var i = 0; i < count; i++)
                    {
                        var(componentType, parameters, sequence) = Descriptors[i];
                        await Renderer.AddComponentAsync(componentType, parameters, sequence.ToString(CultureInfo.InvariantCulture));
                    }

                    // At this point all components have successfully produced an initial render and we can clear the contents of the component
                    // application state store. This ensures the memory that was not used during the initial render of these components gets
                    // reclaimed since no-one else is holding on to it any longer.
                    store.ExistingState.Clear();

                    Log.InitializationSucceeded(_logger);
                }
                catch (Exception ex)
                {
                    // Report errors asynchronously. InitializeAsync is designed not to throw.
                    Log.InitializationFailed(_logger, ex);
                    UnhandledException?.Invoke(this, new UnhandledExceptionEventArgs(ex, isTerminating: false));
                    await TryNotifyClientErrorAsync(Client, GetClientErrorMessage(ex), ex);
                }
            }));
        }