Porting from CEFSharp to WebView2

I have a Windows Presentation Foundation app using CEFSharp as a browser control. I’m porting it to use the new WebView2 control from Microsoft. That’s a workable idea now because it embeds a new Edge object in the WPF app. So,

  • there’s no need to download the whole Chromium Embedded Framework mischegoss which saves download time.
  • WebView2 contains the so-called Chromium Proprietary Codecs (H.264 and AAC).
  • It’s evergreen: when Windows Update pushes a fix to new Edge, the WebView2 control gets the same code. (With CEFSharp the whole app needs to be rereleased.)

What does porting require?

Asynchronous interface

In both CEFSharp and WebView2 there’s a way for browser javascript to call native code. In CEFSharp that interface can be either synchronous or not. In WebView2 it must be asynchronous: every invocation from Javascript returns a promise, so it must be used with await or .then().

Example. Here’s the native code. WebView2 calls it a HostObject.

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()
        {
        }
    }
}

Here’s the .AddHostObjectToScript() line that tells WebView2 to insert it into the page’s Javascript.

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

Here’s the Javascript that uses it. Notice the use of await for everything except property setting.

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

The property setting is not synchronous, however. The setter request still is asynchronously sent to the the HostObject from the Javascript environment. It is also possible to do this explicitly. See this on StackOverflow.

Leave a Comment