WebView2Browser.WebMessageReceived Fails In Async JavaScript

David Day 1 Reputation point
2022-11-04T14:33:25.27+00:00

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.

I am convinced that it is because my JavaScript is asynchronous and the async/await pattern in my front-end is screwing with the WebMessageReceived event handler on the back-end.

Is there any way to "rehook" the WebMessageReceived so that it continues to get messages?

Developer technologies | Windows Forms
Developer technologies | VB
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Jiachen Li-MSFT 34,221 Reputation points Microsoft External Staff
    2022-11-07T07:38:14.647+00:00

    Hi @David Day ,
    Can you ensure that the WebView2Browser.WebMessageReceived event is triggered?
    You may need Implementing the Event-based Asynchronous Pattern.

    Best Regards.
    Jiachen Li

    ----------

    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

  2. David Day 1 Reputation point
    2022-11-08T16:15:08.323+00:00

    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(...))  
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.