Home > Enterprise >  WebView2Browser.WebMessageReceived Not Firing Twice
WebView2Browser.WebMessageReceived Not Firing Twice

Time:11-05

I am communicating between a webpage and a Visual Basic application using a WebView2.

From my JavaScript, I make this call:

app.visualBasic = {};
app.visualBasic.createPromise = () => {
    return new Promise((resolve, reject) => {
        app.visualBasic.promise = { resolve: resolve, reject: reject };
    });
};
app.visualBasic.promise = null;
app.visualBasic.resolve = (literal) => {
    literal = literal || '{}';
    const json = JSON.parse(literal);
    app.visualBasic.promise.resolve(json);
};
app.visualBasic.reject = (literal) => {
    literal = literal || '{}';
    const json = JSON.parse(literal);
    app.visualBasic.promise.reject(json);
};

const populateCategories = async () => {
    const message = {
        Endpoint: '/api/category/get-all'
    };
    chrome.webview.postMessage(message);
    const promise = app.visualBasic.createPromise();

    try {
        const result = await promise;
        if (result?.HttpStatusCode < 200 || result?.HttpStatusCode > 299) {
            throw result?.Body;
        }
        app.data = JSON.parse(result.Body);
    } catch (ex) {
        ex = ex || {};
        app.notification.create('danger', ex.Error || 'Something went wrong getting the categories', ex);
        return;
    } finally {
        app.visualBasic.promise = null;
    }

    // do something with app.data
};

And in my VB.NET's application, I am handling the WebView2Browser.WebMessageReceived event and either sending back app.visualBasic.reject() or app.visualBasic.resolve(...) depending on some business logic using (truncated code):

Private Sub WebView2Browser_WebMessageReceived(sender As Object, e As CoreWebView2WebMessageReceivedEventArgs) Handles WebView2Browser.WebMessageReceived
    Dim webViewSender = DirectCast(sender, WebView2)
    Dim json As String = e.WebMessageAsJson()
    Dim request As WebMessageRequest
    Dim response = New WebMessageResponse()

    Try
        Try
            request = JsonConvert.DeserializeObject(Of WebMessageRequest)(json)
        Catch ex As Exception
            Throw New Exception("Invalid WebMessageRequest", ex)
        End Try

        ' ...
    Catch ex As Exception
        Dim largeLog = New With {request, ex.Message}
        My.Application.Logger.Log(JsonConvert.SerializeObject(largeLog), ex.InnerException)
        webViewSender.ExecuteScriptAsync("app.visualBasic.reject();").Wait()
        Return
    End Try

    WebViewSender.ExecuteScriptAsync($"app.visualBasic.resolve(`{JsonConvert.SerializeObject(response)}`);").Wait()
End Sub

The issue is that running this code once works perfectly fine, but after it runs once any breakpoint setup in my WebView2Browser.WebMessageReceived event handler is not getting triggered.

Is this something wrong with the way I'm using JavaScript promises or is this a bug with the WebView2 control?

CodePudding user response:

After following the "Communication between host and web content" section of the "Get started with WebView2 in WinForms apps" article (here), the suggested method of communicating back to the WebView is to call the CoreWebView2.PostWebMessageAsString or CoreWebView2.PostWebMessageAsJson method and have the JavaScript's window.chrome.webview listen to the message event.

It isn't ideal because I cannot use the async/await pattern to make the code more linear, but it works nonetheless.

Here is an example:

window.chrome.webview.addEventListener('message', e => {
    e = e || {};
    e.data = e.data || {};
    if (e.data.Error) {
        app.notification.create('danger', e.data.Error);
        return;
    }

    // do something
}, false);

and

WebView2Browser.CoreWebView2.PostWebMessageAsJson(JsonConvert.SerializeObject(...))
  • Related