How to Fix “CoreWebView2 Is Null” in WinUI 3 Before ExecuteScriptAsync

How to Fix “CoreWebView2 Is Null” in WinUI 3 Before ExecuteScriptAsync - Step by Step Guide
Figure 1: How to Fix “CoreWebView2 Is Null” in WinUI 3 Before ExecuteScriptAsync - Step by Step Guide

If you are building modern desktop applications using the Windows App SDK and WinUI 3, you likely rely on the WebView2 control to embed web content and execute JavaScript seamlessly. However, one of the most common exceptions encountered by WinUI 3 developers is a NullReferenceException thrown because CoreWebView2 is null when attempting to call ExecuteScriptAsync.

In this comprehensive guide, we will break down why this error occurs, analyze the underlying architecture of Microsoft Edge WebView2, and walk through multiple proven solutions to fix the issue permanently.


Understanding the Problem: Why Is CoreWebView2 Null?

In WinUI 3, the WebView2 element in your XAML file is merely a wrapper framework control. It hosts the underlying Chromium-based Microsoft Edge engine represented by the CoreWebView2 property.

Unlike traditional XAML controls (such as Button or TextBox), the internal browser engine initialization is an asynchronous, out-of-process operation. When your page or window loads:

  1. The XAML UI framework instantiates the WebView2 container.
  2. The underlying browser process (msedgewebview2.exe) initializes independently in the background.
  3. Until that background initialization finishes, MyWebView.CoreWebView2 remains null.

If you invoke MyWebView.ExecuteScriptAsync(...) in your constructor, Loaded event, or a button click handler before the browser engine has initialized, your application crashes immediately with a NullReferenceException.


The most robust and direct way to resolve this issue is to explicitly await the initialization using EnsureCoreWebView2Async() before running any JavaScript.

Step-by-Step Implementation

Here is how to properly structure your C# code-behind:

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Threading.Tasks;

namespace WinUI3WebViewDemo
{
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
        }

        private async void RunScriptButton_Click(object sender, RoutedEventArgs e)
        {
            await ExecuteCustomScriptAsync();
        }

        private async Task ExecuteCustomScriptAsync()
        {
            try
            {
                // 1. Ensure the underlying CoreWebView2 engine is initialized
                if (MyWebView.CoreWebView2 == null)
                {
                    await MyWebView.EnsureCoreWebView2Async();
                }

                // 2. Now it is safe to execute JavaScript
                string script = "document.title;";
                string result = await MyWebView.ExecuteScriptAsync(script);

                System.Diagnostics.Debug.WriteLine($"Document Title: {result}");
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Error executing script: {ex.Message}");
            }
        }
    }
}

Why This Works

EnsureCoreWebView2Async() triggers the background process creation if it has not yet begun, and returns an awaitable task that completes only when CoreWebView2 is non-null and ready for interaction.


Method 2: Listening to CoreWebView2Initialized Event

If you prefer an event-driven architecture rather than inline asynchronous calls, you can listen to the CoreWebView2Initialized event provided by the WebView2 control.

XAML Setup

<Window
    x:Class="WinUI3WebViewDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid>
        <WebView2 x:Name="MyWebView"
                  Source="https://example.com"
                  CoreWebView2Initialized="MyWebView_CoreWebView2Initialized" />
    </Grid>
</Window>

C# Code-Behind

private async void MyWebView_CoreWebView2Initialized(WebView2 sender, CoreWebView2InitializedEventArgs args)
{
    if (args.Exception != null)
    {
        // Handle initialization failure (e.g., missing runtime)
        System.Diagnostics.Debug.WriteLine($"Initialization failed: {args.Exception.Message}");
        return;
    }

    // CoreWebView2 is guaranteed to be non-null here
    await sender.ExecuteScriptAsync("console.log('WebView2 Initialized Successfully!');");
}

Method 3: Executing Scripts After DOM / Page Navigation Completes

Even after CoreWebView2 is initialized, running JavaScript that interacts with specific DOM elements too early might return null or undefined because the page content is still downloading.

To ensure both CoreWebView2 is valid and the web document is fully rendered, attach a handler to the NavigationCompleted event:

public MainWindow()
{
    this.InitializeComponent();
    MyWebView.NavigationCompleted += MyWebView_NavigationCompleted;
}

private async void MyWebView_NavigationCompleted(WebView2 sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs args)
{
    if (args.IsSuccess)
    {
        // CoreWebView2 is available and the page has finished loading
        string pageHeight = await sender.ExecuteScriptAsync("document.body.scrollHeight;");
        System.Diagnostics.Debug.WriteLine($"Rendered Page Height: {pageHeight}");
    }
}

Common Pitfalls and Best Practices

To keep your WinUI 3 WebView2 integration smooth and crash-free, keep these tips in mind:

1. Avoid Calling ExecuteScriptAsync in Window Constructors

Never call ExecuteScriptAsync directly in your MainWindow() or Page constructor. The visual tree is not yet loaded, and the web view initialization pipeline has not started.

2. Handle Custom Environments and User Data Folders

If you need custom flags or a specific storage path for browser cache and cookies, create a custom CoreWebView2Environment before calling EnsureCoreWebView2Async:

var customEnv = await Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateWithOptionsAsync(
    browserExecutableFolder: null,
    userDataFolder: System.IO.Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "WebView2Data"),
    options: new Microsoft.Web.WebView2.Core.CoreWebView2EnvironmentOptions()
);

await MyWebView.EnsureCoreWebView2Async(customEnv);

3. Verify Thread Affinity

WebView2 APIs must be called on the UI thread. If you are dispatching work from background tasks or thread pool threads, ensure you use DispatcherQueue.TryEnqueue() to return execution to the UI thread before calling ExecuteScriptAsync.


Summary

The CoreWebView2 is null error in WinUI 3 is not a bug; it is an expected characteristic of asynchronous browser runtime initialization. By explicitly using await MyWebView.EnsureCoreWebView2Async(), listening to CoreWebView2Initialized, or awaiting NavigationCompleted, you can safely execute scripts and build reliable, high-performance desktop hybrid apps.

CF

Written by DEVINFOTECH Technical Team

Verified file conversion guides, technical specs, and troubleshooting solutions engineered for Windows desktop users.

Comments

← Newer Posts Older Posts →

Stay Ahead in Tech & Productivity

Join 15,000+ Windows power users receiving weekly document conversion hacks, error fix tutorials, and exclusive desktop software updates directly to your inbox.

Action completed successfully!