WebView2:在 C# 中从 Javascript 代码设置对象属性

Posted

技术标签:

【中文标题】WebView2:在 C# 中从 Javascript 代码设置对象属性【英文标题】:WebView2: Setting object properties in C# from Javascript code 【发布时间】:2021-10-07 21:44:30 【问题描述】:

这是this question 的后续内容。

我正在将 WPF 应用程序从 CEFSharp 移植到 WebView2。我有一个 HostObject 需要从 WebView2 窗口中的 js 访问。就是这样,被剥离了。

using System;
using System.Runtime.InteropServices;

namespace webview2Demo

    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class Api
    
        public string Username  get; set; 
        public string Version = "1.1.1";
        public Api()  //ctor
        
        
    

我可以在 WebView2 控件的 NavigationStarting 事件中成功使用这一行来使对象在 javascript 中可见。到目前为止一切顺利。

webView.CoreWebView2.AddHostObjectToScript("api", new API());

我可以像这样检索公共属性和成员。到目前为止一切顺利。

(async function foo () 
  const api = chrome.webview.hostObjects.api
  const ver = await api.Version
  alert (ver)
)();

我的问题:我能否在没有任何异步竞争条件或死锁风险的情况下可靠地设置这样的属性? api.Username = 'whoever' 它似乎有效,但我没有发现它记录在案。

(async function foo () 
  const api = chrome.webview.hostObjects.api
  api.Username = 'whoever'
  const user = await api.Username
  alert (user)
)();

文档说 HostObject 是通过 Promises 公开的。 我击中二传手是否正确?

【问题讨论】:

【参考方案1】:

当您在 JavaScript 代理上为通过 CoreWebView2.AddHostObjectToScript 创建的主机对象设置属性时,与获取属性或调用方法不同,分配返回的值与分配的相同,而不是表示该分配完成的承诺。属性分配确实会生成一条消息,发送回 WebView2 主机应用程序进程,并且属性将被分配,但您不会承诺在其完成时告诉您。

设置主机属性

或者,您可以使用setHostProperty,该方法将执行属性分配并返回将在属性分配完成时解析的promise。

(async function foo () 
  const api = chrome.webview.hostObjects.api
  await api.setHostProperty('Username', 'whoever');
  const user = await api.Username
  alert (user)
)();

同步代理

还有同步版本的代理。在任何地方,异步代理都会返回一个 Promise,同步代理会阻止 JavaScript 线程等待来自 WebView2 主机进程的响应。通常,您不希望阻塞等待跨进程调用的 JavaScript 线程,但在某些情况下它可能更实用或可接受。异步代理有一个sync 方法,它将返回代理的同步版本(异步)。

(async function foo () 
  // Note the one await call to get from async proxies to sync proxies
  const syncHostObjects = await chrome.webview.hostObjects.sync;
  const api = syncHostObjects.api;
  api.Username = 'whoever';
  const user = api.Username
  alert (user)
)();

依靠队列

由于所有 JavaScript 代理消息都在同一个队列中传输,并且必须在 WebView2 主机应用程序进程中的同一个线程上处理,因此使用属性设置器而不等待它完成然后调用 getter 可能会仍然强制获取消息等待设置完成并且您的原始代码很好。

【讨论】:

以上是关于WebView2:在 C# 中从 Javascript 代码设置对象属性的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 编码环境中使用 WebView2 时禁用 Web 安全

WebView2 (WPF) - 从本地文件夹加载网站并调用 C# 函数并调用 JS 函数

如何在 Webview2 中使用透明度?

在 UIWebView 中从 JS 返回一个 var

在 C# 代码中从 GAC 卸载

如何在 C# 中从 ECDsa 获取公钥