WebMessageReceived 事件处理程序中的 SetVirtualHostName 不起作用

SetVirtualHostName within WebMessageReceived event handler doesn't work

我正在尝试使用从 WebView2 的包含应用程序传入的源在 WebView2 中动态创建图像。

源图像存在于文件系统的任意位置。为了允许 WebView2 访问图像,我使用 SetVirtualHostNameToFolderMapping,它将 Web 视图中的主机名映射到某个文件夹。

我希望仅在使用 postMessageWebMessageReceived event, as described here.

从 webview 内部进行一些交互后才会发生这种情况

如果我在 WebMessageReceived 处理程序之外调用 SetVirtualHostNameToFolderMapping,即使我使用 HTML 导航到 HTML =15=], webview加载图片。

但是如果我在 WebMessageReceived 处理程序中调用 SetVirtualHostNameToFolderMapping

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

webview找不到图片;它失败了:

Failed to load resource: net::ERR_NAME_NOT_RESOLVED

我该如何调试呢?我可以使用其他替代方法来做类似的事情吗?


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>

代码隐藏:

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>

我为此提交了 issue。根据响应,记录了此行为:

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. (source)

但是可以创建(和重新创建)符号 link 到不同的目标路径,并将虚拟主机名映射到该符号 link。虚拟主机映射使用当前 symlink 目标。

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

Directory.CreateDirectory(symlinkPath);

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

webview.CoreWebView2.WebMessageReceived += (s, e) => {
    Directory.Delete(symlinkPath);
    Directory.CreateSymbolicLink(symlinkPath, @"C:\path\to\target\directory");
    webview.CoreWebView2.PostWebMessageAsString(@"breakpoint.bmp");
};