Using WebView2 call C# methods (async and sync) with complex parameters and return values from TS/JS!
There currently is no NuGet and npm packages, instead copy the WebView2BetterBridge\BetterBridge.cs to your C# project and web-ui\src\betterBridge.ts to your frontend project.
Note: For this solution to work with async methods you need to be on WebView2 1.0.1293.44 or later.
The documentation here is just a very light overview, for full details check the sample projects.
- 
Create a regular class that contains all the methods you can call from TS/JS (see SampleBridge.csfor an example). Both async and sync methods with complex object parameters and return values will work.
- 
Register it by calling: webView2.CoreWebView2.AddHostObjectToScript("bridge", new BetterBridge(new MyBridge(), webView2)); Notice how BetterBridge wraps your own bridge class. 
Note: The TS/JS method on the bridge should use camelCase.
// TypeScript
import { createBridge } from "./betterBridge";
const bridge = createBridge("bridge");
const result = await bridge.helloWorldAsync(99, "abc", {
  text: "hello from JS!",
  sent: new Date(),
});// C#
public async Task<Message> HelloWorldAsync(int someData, string moreData, Message message)
{
    var msg = new Message()
    {
        Text = $"Hi from C#! Thank you for the data: {message.Text} {message.Sent} {someData} and {moreData}.",
        Sent = DateTime.Now
    };
    await Task.Delay(500);
    return msg;
}Note: The TS/JS method on the bridge should use camelCase.
Note: Even though the C# method is sync it's still resolved to a Promise that we have to await. This is the recommended way since we do not want to lock up the UI.
// TypeScript
import { createBridge } from "./betterBridge";
const bridge = createBridge("bridge");
const result = await bridge.helloWorld(99, "abc", {
  text: "hello from JS!",
  sent: new Date(),
});// C#
public Message HelloWorld(int someData, string moreData, Message message)
{
    return new Message()
    {
        Text = $"Hi from C#! Thank you for the data: {message.Text} {message.Sent} {someData} and {moreData}.",
        Sent = DateTime.Now
    };
}Makes it a bit easier to send messages from C# to TS/JS instead of using webView2.CoreWebView2.PostWebMessageAsJson directly.
// C#
var messageSender = new BetterBridgeMessageSender(webView2);
messageSender.SendMessage("message", new Message() { Text = "I want to report something", Sent = DateTime.Now });// TypeScript
import { createBridge } from "./betterBridge";
const bridge = createBridge("bridge");
bridge.addMessageHandler((type, data) => {
  console.log("Got message", type, data);
});Uses some reflection under the hood but when testing I saw very small performance differences often in the range of 0.1-0.5 ms. But your results may vary 😊.