Example #1
0
        private async Task RunOnNavigateAsync(string path)
        {
            // If this router instance does not provide an OnNavigateAsync parameter
            // then we render the component associated with the route as per usual.
            if (!OnNavigateAsync.HasDelegate)
            {
                return;
            }

            // If we've already invoked a task and stored its CTS, then
            // cancel the existing task.
            _onNavigateCts?.Dispose();

            // Create a new cancellation token source for this instance
            _onNavigateCts = new CancellationTokenSource();
            var navigateContext = new NavigationContext(path, _onNavigateCts.Token);

            // Create a cancellation task based on the cancellation token
            // associated with the current running task.
            var cancellationTaskSource = new TaskCompletionSource();

            navigateContext.CancellationToken.Register(state =>
                                                       ((TaskCompletionSource)state).SetResult(), cancellationTaskSource);

            var task = OnNavigateAsync.InvokeAsync(navigateContext);

            // If the user provided a Navigating render fragment, then show it.
            if (Navigating != null && task.Status != TaskStatus.RanToCompletion)
            {
                _renderHandle.Render(Navigating);
            }

            await Task.WhenAny(task, cancellationTaskSource.Task);
        }
Example #2
0
        internal async ValueTask RunOnNavigateAsync(string path, bool isNavigationIntercepted)
        {
            // Cancel the CTS instead of disposing it, since disposing does not
            // actually cancel and can cause unintended Object Disposed Exceptions.
            // This effectivelly cancels the previously running task and completes it.
            _onNavigateCts?.Cancel();
            // Then make sure that the task has been completely cancelled or completed
            // before starting the next one. This avoid race conditions where the cancellation
            // for the previous task was set but not fully completed by the time we get to this
            // invocation.
            await _previousOnNavigateTask;

            var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

            _previousOnNavigateTask = tcs.Task;

            var okToRoute = this.RouterSessionService.CanRoute(this.NavigationManager.Uri, _locationAbsolute, out bool reRoute);

            //  Need to check if we can route
            if (!OnNavigateAsync.HasDelegate && okToRoute)
            {
                Refresh(isNavigationIntercepted);
            }

            _onNavigateCts = new CancellationTokenSource();
            var navigateContext = new NavigationContext(path, _onNavigateCts.Token);

            var cancellationTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

            navigateContext.CancellationToken.Register(state =>
                                                       ((TaskCompletionSource)state).SetResult(), cancellationTcs);

            try
            {
                // Task.WhenAny returns a Task<Task> so we need to await twice to unwrap the exception
                var task = await Task.WhenAny(OnNavigateAsync.InvokeAsync(navigateContext), cancellationTcs.Task);

                await task;
                tcs.SetResult();
                //  Need to check if we can route
                if (okToRoute)
                {
                    Refresh(isNavigationIntercepted);
                }
            }
            catch (Exception e)
            {
                _renderHandle.Render(builder => ExceptionDispatchInfo.Throw(e));
            }
            // if reroute then do it and exit
            if (reRoute)
            {
                await ReNavigateAsync();
            }
        }
        internal async ValueTask RunOnNavigateAsync(string path, bool isNavigationIntercepted)
        {
            Logger.LogDebug("RunOnNavigateAsync with path {path}", path);
            // Cancel the CTS instead of disposing it, since disposing does not
            // actually cancel and can cause unintended Object Disposed Exceptions.
            // This effectivelly cancels the previously running task and completes it.
            _onNavigateCts?.Cancel();
            // Then make sure that the task has been completely cancelled or completed
            // before starting the next one. This avoid race conditions where the cancellation
            // for the previous task was set but not fully completed by the time we get to this
            // invocation.
            await _previousOnNavigateTask;

            var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

            _previousOnNavigateTask = tcs.Task;

            if (!OnNavigateAsync.HasDelegate)
            {
                Logger.LogDebug("RunOnNavigateAsync - !OnNavigateAsync.HasDelegate");
                await Refresh(isNavigationIntercepted);
            }

            _onNavigateCts = new CancellationTokenSource();
            var navigateContext = new NavigationContext(path, _onNavigateCts.Token);

            var cancellationTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

            navigateContext.CancellationToken.Register(state =>
                                                       ((TaskCompletionSource)state).SetResult(), cancellationTcs);

            try
            {
                // Task.WhenAny returns a Task<Task> so we need to await twice to unwrap the exception
                var task = await Task.WhenAny(OnNavigateAsync.InvokeAsync(navigateContext), cancellationTcs.Task);

                await task;
                tcs.SetResult();
                Logger.LogDebug("RunOnNavigateAsync - Refresh(isNavigationIntercepted)");
                await Refresh(isNavigationIntercepted);
            }
            catch (Exception e)
            {
                Logger.LogError(e, "RunOnNavigateAsync - Catch");
                _renderHandle.Render(builder => ExceptionDispatchInfo.Throw(e));
            }
        }
Example #4
0
        private async ValueTask <bool> RunOnNavigateAsync(string path, Task previousOnNavigate)
        {
            // If this router instance does not provide an OnNavigateAsync parameter
            // then we render the component associated with the route as per usual.
            if (!OnNavigateAsync.HasDelegate)
            {
                return(true);
            }

            // If we've already invoked a task and stored its CTS, then
            // cancel that existing CTS.
            _onNavigateCts?.Cancel();
            // Then make sure that the task has been completed cancelled or
            // completed before continuing with the execution of this current task.
            await previousOnNavigate;

            // Create a new cancellation token source for this instance
            _onNavigateCts = new CancellationTokenSource();
            var navigateContext = new NavigationContext(path, _onNavigateCts.Token);

            // Create a cancellation task based on the cancellation token
            // associated with the current running task.
            var cancellationTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

            navigateContext.CancellationToken.Register(state =>
                                                       ((TaskCompletionSource)state).SetResult(), cancellationTcs);

            var task = OnNavigateAsync.InvokeAsync(navigateContext);

            // If the user provided a Navigating render fragment, then show it.
            if (Navigating != null && task.Status != TaskStatus.RanToCompletion)
            {
                _renderHandle.Render(Navigating);
            }

            var completedTask = await Task.WhenAny(task, cancellationTcs.Task);

            return(task == completedTask);
        }