Skip to content

[Problem/Bug]: Race condition when disposing and creating WebView2 instances with different environment options #5229

Open
@JBridenbaugh

Description

@JBridenbaugh

What happened?

I am using WebView2 in a WPF application to interact with our Identity provider service. When the navigation url host changes, I dispose the old instance and create a new instance with a different setting configured in CoreWebView2EnvironmentOptions. The user data folder and browser executable folder remain the same. When I call EnsureCoreWebView2Async I get this exception:

System.Runtime.InteropServices.COMException (0x8007139F): The group or resource is not in the correct state to perform the requested operation. (0x8007139F)
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode)
   at Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateCoreWebView2ControllerAsync(IntPtr ParentWindow)
   at Microsoft.Web.WebView2.Wpf.WebView2.Microsoft.Web.WebView2.Wpf.IWebView2Private.InitializeController(IntPtr parent_window, CoreWebView2ControllerOptions controllerOptions)
   at Microsoft.Web.WebView2.Wpf.WebView2Base.<>c__DisplayClass32_0.<<EnsureCoreWebView2Async>g__Init|0>d.MoveNext()
--- End of stack trace from previous location ---
   at InitializeWebViewException.WebViewManager.<>c__DisplayClass2_0.<<CreateWebView>b__0>d.MoveNext() in C:\repos\InitializeWebViewException\WebViewManager.cs:line 43

Importance

Important. My app's user experience is significantly compromised.

Runtime Channel

Stable release (WebView2 Runtime)

Runtime Version

135.0.3179.98

SDK Version

1.0.3179.45

Framework

WPF

Operating System

Windows 11

OS Version

10.0.26100

Repro steps

This issue can be consistently reproduced with the attached WPF project.

InitializeWebViewException.zip

  1. Run the program and navigate to the default url (https://microsoft.com)
  2. Change the navigation url to something with a different host
  3. A message box with an error will appear

Image

Here is the code for the test project if that will be easier.

MainWindow.xaml

<Window x:Class="InitializeWebViewException.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:InitializeWebViewException"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid x:Name="MainGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" 
                    Orientation="Horizontal">
            <TextBox Name="TextBox_NavigationUrl"
                     Width="300"
                     Margin="5"
                     Text="https://microsoft.com" />
            <Button Name="Button_Navigate"
                    Margin="5"
                    Content="Navigate"
                    Click="Button_Navigate_Click" />

        </StackPanel>
        <Grid Grid.Row="1"
              Name="WebViewContainer" />
    </Grid>
</Window>

MainWindow.xaml.cs

using Microsoft.Web.WebView2.Wpf;
using System.Windows;

namespace InitializeWebViewException
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly WebViewManager _webViewManager = new();

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Navigate_Click(object sender, RoutedEventArgs e)
        {
            WebViewContainer.Children.Clear();

            WebView2 webView = _webViewManager.GetWebView(TextBox_NavigationUrl.Text);
            WebViewContainer.Children.Add(webView);
        }
    }
}

WebViewManager.cs

using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.Wpf;
using System.IO;
using System.Windows;

namespace InitializeWebViewException
{
    internal class WebViewManager
    {
        private WebView2? _webView;

        public WebView2 GetWebView(string navigationUrl)
        {
            if (_webView == null || ShouldCreateNewWebView())
            {
                Reset();

                _webView = CreateWebView(navigationUrl);
            }
            // Will never happen in example code
            else
                _webView.CoreWebView2.Navigate(navigationUrl);

            return _webView;
        }

        private static WebView2 CreateWebView(string navigationUrl)
        {
            WebView2 webView = new();

            webView.Loaded += async delegate
            {
                try
                {
                    string userDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "WebView2");

                    var webViewEnvironment = await CoreWebView2Environment.CreateAsync(browserExecutableFolder: null, userDataFolder, new CoreWebView2EnvironmentOptions()
                    {
                        // Represents an environment option that changes between instances
                        AdditionalBrowserArguments = $"--auth-server-allowlist=\"{new Uri(navigationUrl).Host}\""
                    });

                    await webView.EnsureCoreWebView2Async(webViewEnvironment);
                    webView.CoreWebView2.Navigate(navigationUrl);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"Error creating WebView2: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            };

            return webView;
        }

        // Hard coded to reproduce the issue
        private static bool ShouldCreateNewWebView() => true;

        private void Reset()
        {
            _webView?.Dispose();
            _webView = null;
        }
    }
}

This is a timing issue that stops happening if you put a 100 millisecond delay anywhere between the Reset() call and the await webView.EnsureCoreWebView2Async(webViewEnvironment) call.

Repros in Edge Browser

No, issue does not reproduce in the corresponding Edge version

Regression

Don't know

Last working version (if regression)

No response

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions