Skip to content
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

Host set with SetVirtualHostName within WebMessageReceived event handler isn't recognized #2456

Closed
zspitz opened this issue May 13, 2022 · 2 comments
Assignees
Labels
bug Something isn't working

Comments

@zspitz
Copy link

zspitz commented May 13, 2022

Description
I'm trying to use SetVirtualHostNameToFolderMapping to map a host name to a local folder, from within a WebMessageReceived event handler. If I then create an image within the webview with an src referencing the mapped hostname, the mapping is ignored, and DevTools console displays: Failed to load resource: net::ERR_NAME_NOT_RESOLVED.

Version
SDK: 1.0.1248-prerelease
Runtime: 101.0.1210.39 (Official build) (64-bit)
Framework: WPF
OS: Windows 10 Home 21H2 (build 19044.1706)

Repro Steps

  1. Call postMessage from JavaScript within the webview.
  2. In the handler WebMessageReceived, call SetVirtualHostNameToFolderMapping
  3. In the mesage event listener, set the src of an image to something in the mapped host folder.

Additional context

Project illustrating the problem: _testWebviewDialogs.zip

SO question

XAML:

<Window x:Class="_testWebviewDialogs.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wv="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf">
    <wv:WebView2 x:Name="webview" />
</Window>

Code behind:

using System.IO;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Web.WebView2.Core;

namespace _testWebviewDialogs;
public partial class MainWindow : Window {
    public MainWindow() {
        InitializeComponent();
        Loaded += async (s, e) => await initializeAsync();
    }

    private async Task initializeAsync() {
        await webview.EnsureCoreWebView2Async();
        webview.CoreWebView2.WebMessageReceived += (s, e) => {
            webview.CoreWebView2.SetVirtualHostNameToFolderMapping(
                "assets",
                @"C:\path\to\folder",
                CoreWebView2HostResourceAccessKind.Allow
            );
            webview.CoreWebView2.PostWebMessageAsString(@"breakpoint.bmp");
        };

        var html = await File.ReadAllTextAsync("container.html");
        webview.NavigateToString(html);
    }
}

container.html:

<!DOCTYPE html>
<html>
<body>
    <button id="button1">Click me</button>
    <img id ="img1" src="" />
    <script>
        document.getElementById("button1").addEventListener('click', ev => {
            chrome.webview.postMessage('source');
        });
        window.chrome.webview.addEventListener('message', event => {
            document.getElementById('img1').src = `https://assets/${event.data}`;
        });
    </script>
</body>
</html>
@zspitz zspitz added the bug Something isn't working label May 13, 2022
@champnic
Copy link
Member

Hey @zspitz - thanks for the bug report!

This limitation is currently expected when using SetVirtualHostNameToFolderMapping:
"As the resource loaders for the current page might have already been created and running, changes to the mapping might not be applied to the current page and a reload of the page is needed to apply the new mapping."
From: https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.setvirtualhostnametofoldermapping?view=webview2-dotnet-1.0.1210.39#remarks

If you reload the page first, or set the mapping before navigating to your page, does the mapping work as expected?

@zspitz
Copy link
Author

zspitz commented May 15, 2022

@champnic I know that setting the mapping before navigation works; and reloading would also probably work. But the virtual host target path may change multiple times over the lifetime of the application, and I don't really want to reload each time.

But instead of removing and recreating the virtual host path, I can create (and recreate) a symbolic link to the target path as needed. Then, at application start, I can map the virtual host to the symbolic link:

var symlinkPath =
    Path.Combine(
        Path.GetDirectoryName(
            Assembly.GetExecutingAssembly().Location!
        )!,
        "assets"
    );

// In order to map the virtual host name, the directory has to exist
// Creating a dummy folder here
Directory.CreateDirectory(symlinkPath);

webview.CoreWebView2.SetVirtualHostNameToFolderMapping(
    "assets",
    symlinkPath,
    CoreWebView2HostResourceAccessKind.Allow
);

webview.CoreWebView2.WebMessageReceived += (s, e) => {
    Directory.Delete(symlinkPath);
    Directory.CreateSymbolicLink(symlinkPath, @"C:\Users\Spitz\Desktop\testmd");
    webview.CoreWebView2.PostWebMessageAsString(@"breakpoint.bmp");
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants