CoreWebView2.AddHostObjectToScript(String, Object) Method

Definition

Adds the provided host object to script running in the WebView with the specified name.

public void AddHostObjectToScript (string name, object rawObject);
member this.AddHostObjectToScript : string * obj -> unit
Public Sub AddHostObjectToScript (name As String, rawObject As Object)

Parameters

name
String

The name of the host object.

rawObject
Object

The host object to be added to script.

Examples

To create a IDispatch implementing class in C# use the following attributes on each class you intend to expose.

// Bridge and BridgeAnotherClass are C# classes that implement IDispatch and works with AddHostObjectToScript.
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class BridgeAnotherClass
{
    // Sample property.
    public string Prop { get; set; } = "Example";
}

[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class Bridge
{
    public string Func(string param)
    {
        return "Example: " + param;
    }

    public BridgeAnotherClass AnotherObject { get; set; } = new BridgeAnotherClass();

    // Sample indexed property.
    [System.Runtime.CompilerServices.IndexerName("Items")]
    public string this[int index]
    {
        get { return m_dictionary[index]; }
        set { m_dictionary[index] = value; }
    }
    private Dictionary<int, string> m_dictionary = new Dictionary<int, string>();
}

Then add instances of those classes via AddHostObjectToScript(String, Object):

webView.CoreWebView2.AddHostObjectToScript("bridge", new Bridge());

And then in script you can call the methods, and access those properties of the objects added via AddHostObjectToScript(String, Object):

// Find added objects on the hostObjects property
const bridge = chrome.webview.hostObjects.bridge;

// Call a method and pass in a parameter.
// The result is another proxy promise so you must await to get the result.
console.log(await bridge.Func("testing..."));

// A property may be another object as long as its class also implements
// IDispatch.
// Getting a property also gets a proxy promise you must await.
const propValue = await bridge.AnotherObject.Prop;
console.log(propValue);

// Indexed properties
let index = 123;
bridge[index] = "test";
let result = await bridge[index];
console.log(result);

Remarks

Host objects are exposed as host object proxies via window.chrome.webview.hostObjects.{name}. Host object proxies are promises and will resolve to an object representing the host object. Only the COM visible objects/properties/methods can be accessed from script. The app can control which part of .NET objects are exposed using ComVisibleAttribute.

JavaScript code in the WebView will be able to access appObject as following and then access attributes and methods of appObject.

Note that while simple types, IDispatch and array are supported, and IUnknown objects that also implement IDispatch are treated as IDispatch, generic IUnknown, VT_DECIMAL, or VT_RECORD variant is not supported. Remote JavaScript objects like callback functions are represented as an VT_DISPATCH VARIANT with the object implementing IDispatch. The JavaScript callback method may be invoked using DISPID_VALUE for the DISPID. Nested arrays are supported up to a depth of 3. Arrays of by reference types are not supported. VT_EMPTY and VT_NULL are mapped into JavaScript as null. In JavaScript null and undefined are mapped to VT_EMPTY.

Additionally, all host objects are exposed as window.chrome.webview.hostObjects.sync.{name}. Here the host objects are exposed as synchronous host object proxies. These are not promises and calls to functions or property access synchronously block running script waiting to communicate cross process for the host code to run. Accordingly this can result in reliability issues and it is recommended that you use the promise based asynchronous window.chrome.webview.hostObjects.{name} API described above.

Synchronous host object proxies and asynchronous host object proxies can both proxy the same host object. Remote changes made by one proxy will be reflected in any other proxy of that same host object whether the other proxies and synchronous or asynchronous.

While JavaScript is blocked on a synchronous call to native code, that native code is unable to call back to JavaScript. Attempts to do so will fail with HRESULT_FROM_WIN32(ERROR_POSSIBLE_DEADLOCK).

Host object proxies are JavaScript Proxy objects that intercept all property get, property set, and method invocations. Properties or methods that are a part of the Function or Object prototype are run locally. Additionally any property or method in the array chrome.webview.hostObjects.options.forceLocalProperties will also be run locally. This defaults to including optional methods that have meaning in JavaScript like toJSON and Symbol.toPrimitive. You can add more to this array as required.

There's a method chrome.webview.hostObjects.cleanupSome that will best effort garbage collect host object proxies.

The chrome.webview.hostObjects.options object provides the ability to change some functionality of host objects.

Options propertyDetails
forceLocalProperties This is an array of host object property names that will be run locally, instead of being called on the native host object. This defaults to then, toJSON, Symbol.toString, and Symbol.toPrimitive. You can add other properties to specify that they should be run locally on the JavaScript host object proxy.
log This is a callback that will be called with debug information. For example, you can set this to console.log.bind(console) to have it print debug information to the console to help when troubleshooting host object usage. By default this is null.
shouldSerializeDates By default this is false, and JavaScript Date objects will be sent to host objects as a string using JSON.stringify. You can set this property to true to have Date objects properly serialize as a System.DateTime when sending to the .NET host object, and have System.DateTime properties and return values create a JavaScript Date object.
defaultSyncProxy When calling a method on a synchronous proxy, the result should also be a synchronous proxy. But in some cases, the sync/async context is lost (for example, when providing to native code a reference to a function, and then calling that function in native code). In these cases, the proxy will be asynchronous, unless this property is set.
forceAsyncMethodMatches This is an array of regular expressions. When calling a method on a synchronous proxy, the method call will be performed asynchronously if the method name matches a string or regular expression in this array. Setting this value to Async will make any method that ends with Async be an asynchronous method call. If an async method doesn't match here and isn't forced to be asynchronous, the method will be invoked synchronously, blocking execution of the calling JavaScript and then returning the resolution of the promise, rather than returning a promise.
ignoreMemberNotFoundError By default, an exception is thrown when attempting to get the value of a proxy property that doesn't exist on the corresponding native class. Setting this property to true switches the behavior to match Chakra WinRT projection (and general JavaScript) behavior of returning undefined with no error.

Host object proxies additionally have the following methods which run locally:

Method nameDetails
applyHostFunction, getHostProperty, setHostProperty Perform a method invocation, property get, or property set on the host object. You can use these to explicitly force a method or property to run remotely if there is a conflicting local method or property. For instance, proxy.toString() will run the local toString method on the proxy object. But proxy.applyHostFunction('toString') runs toString on the host proxied object instead.
getLocalProperty, setLocalProperty Perform property get, or property set locally. You can use these methods to force getting or setting a property on the host object proxy itself rather than on the host object it represents. For instance, proxy.unknownProperty will get the property named unknownProperty from the host proxied object. But proxy.getLocalProperty('unknownProperty') will get the value of the property unknownProperty on the proxy object itself.
sync Asynchronous host object proxies expose a sync method which returns a promise for a synchronous host object proxy for the same host object. For example, chrome.webview.hostObjects.sample.methodCall() returns an asynchronous host object proxy. You can use the sync method to obtain a synchronous host object proxy instead: const syncProxy = await chrome.webview.hostObjects.sample.methodCall().sync()
async Synchronous host object proxies expose an async method which blocks and returns an asynchronous host object proxy for the same host object. For example, chrome.webview.hostObjects.sync.sample.methodCall() returns a synchronous host object proxy. Calling the async method on this blocks and then returns an asynchronous host object proxy for the same host object: const asyncProxy = chrome.webview.hostObjects.sync.sample.methodCall().async()
then Asynchronous host object proxies have a then method. This allows them to be awaitable. then will return a promise that resolves with a representation of the host object. If the proxy represents a JavaScript literal then a copy of that is returned locally. If the proxy represents a function then a non-awaitable proxy is returned. If the proxy represents a JavaScript object with a mix of literal properties and function properties, then the a copy of the object is returned with some properties as host object proxies.

All other property and method invocations (other than the above Remote object proxy methods, forceLocalProperties list, and properties on Function and Object prototypes) are run remotely. Asynchronous host object proxies return a promise representing asynchronous completion of remotely invoking the method, or getting the property. The promise resolves after the remote operations complete and the promises resolve to the resulting value of the operation. Synchronous host object proxies work similarly but block JavaScript execution and wait for the remote operation to complete.

Setting a property on an asynchronous host object proxy works slightly differently. The set returns immediately and the return value is the value that will be set. This is a requirement of the JavaScript Proxy object. If you need to asynchronously wait for the property set to complete, use the setHostProperty method which returns a promise as described above. Synchronous object property set property synchronously blocks until the property is set.

Exposing host objects to script has security risk. Please follow best practices.

Applies to

See also