File: Services\WebViewNavigationManager.cs
Web Access
Project: src\src\Components\WebView\WebView\src\Microsoft.AspNetCore.Components.WebView.csproj (Microsoft.AspNetCore.Components.WebView)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.Extensions.Logging;
 
namespace Microsoft.AspNetCore.Components.WebView.Services;
 
internal sealed partial class WebViewNavigationManager : NavigationManager
{
    private readonly ILogger _logger;
    private IpcSender _ipcSender;
 
    public WebViewNavigationManager(ILogger<WebViewNavigationManager> logger)
    {
        _logger = logger;
    }
 
    public void AttachToWebView(IpcSender ipcSender, string baseUrl, string initialUrl)
    {
        _ipcSender = ipcSender;
        Initialize(baseUrl, initialUrl);
    }
 
    public void LocationUpdated(string newUrl, string? state, bool intercepted)
    {
        Uri = newUrl;
        HistoryEntryState = state;
        NotifyLocationChanged(intercepted);
    }
 
    public void HandleLocationChanging(int callId, string uri, string? state, bool intercepted)
    {
        _ = HandleLocationChangingAsync();
 
        async Task HandleLocationChangingAsync()
        {
            try
            {
                var shouldContinueNavigation = await NotifyLocationChangingAsync(uri, state, intercepted);
 
                if (!shouldContinueNavigation)
                {
                    Log.NavigationCanceled(_logger, uri);
                }
 
                _ipcSender.EndLocationChanging(callId, shouldContinueNavigation);
            }
            catch (Exception ex)
            {
                // We shouldn't ever reach this since exceptions thrown from handlers are caught in InvokeLocationChangingHandlerAsync.
                // But if some other exception gets thrown, we still want to know about it.
                Log.NavigationFailed(_logger, uri, ex);
                _ipcSender.NotifyUnhandledException(ex);
            }
        }
    }
 
    protected override void NavigateToCore(string uri, NavigationOptions options)
    {
        _ = PerformNavigationAsync();
 
        async Task PerformNavigationAsync()
        {
            try
            {
                var shouldContinueNavigation = await NotifyLocationChangingAsync(uri, options.HistoryEntryState, false);
 
                if (!shouldContinueNavigation)
                {
                    Log.NavigationCanceled(_logger, uri);
                    return;
                }
 
                _ipcSender.Navigate(uri, options);
            }
            catch (Exception ex)
            {
                // We shouldn't ever reach this since exceptions thrown from handlers are handled in HandleLocationChangingHandlerException.
                // But if some other exception gets thrown, we still want to know about it.
                Log.NavigationFailed(_logger, uri, ex);
                _ipcSender.NotifyUnhandledException(ex);
            }
        }
    }
 
    /// <inheritdoc />
    public override void Refresh(bool forceReload = false)
    {
        _ipcSender.Refresh(forceReload);
    }
 
    protected override void HandleLocationChangingHandlerException(Exception ex, LocationChangingContext context)
    {
        Log.NavigationFailed(_logger, context.TargetLocation, ex);
        _ipcSender.NotifyUnhandledException(ex);
    }
 
    protected override void SetNavigationLockState(bool value)
    {
        _ipcSender.SetHasLocationChangingListeners(value);
    }
 
    private static partial class Log
    {
        [LoggerMessage(1, LogLevel.Debug, "Navigation canceled when changing the location to {Uri}", EventName = "NavigationCanceled")]
        public static partial void NavigationCanceled(ILogger logger, string uri);
 
        [LoggerMessage(2, LogLevel.Error, "Navigation failed when changing the location to {Uri}", EventName = "NavigationFailed")]
        public static partial void NavigationFailed(ILogger logger, string uri, Exception exception);
    }
}