Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EnsureCoreWebView2Async always throws exception. #1778

Closed
christopherbadman opened this issue Sep 29, 2021 · 30 comments
Closed

EnsureCoreWebView2Async always throws exception. #1778

christopherbadman opened this issue Sep 29, 2021 · 30 comments
Assignees
Labels
bug Something isn't working

Comments

@christopherbadman
Copy link

christopherbadman commented Sep 29, 2021

Description
A call to Microsoft.Web.WebView2.Wpf.WebView2.EnsureCoreWebView2Async() throws a COMException every time. It feels like there's some state on my system that is stuck leading WebView2 to think that it's already in use/not suitable to be created?

The group or resource is not in the correct state to perform the requested operation. (Exception from HRESULT: 0x8007139F)
System.Runtime.InteropServices.COMException (0x8007139F): The group or resource is not in the correct state to perform the requested operation. (Exception from HRESULT: 0x8007139F)
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at Microsoft.Web.WebView2.Core.CoreWebView2Environment.<CreateCoreWebView2ControllerAsync>d__53.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Web.WebView2.Wpf.WebView2.<>c__DisplayClass26_0.<<EnsureCoreWebView2Async>g__Init|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Tdx.Kraken.Wpf.Renderers.WebView2Renderer.<LoadUrl>d__7.MoveNext()

Version
SDK: 1.0.955-prerelease
Runtime: 94.0.992.31
Framework: WPF
OS: Win10 (10.0.19042 Build 19042)

Repro Steps
Difficult to know what actions have led to my system being in this state. It seemed to begin after I had launched a debug session from VS Code, using the launch configuration

    {
         "name": "wpf",
         "request": "launch",
         "type": "edge",
         "url": "http://localhost:3000",
         "runtimeExecutable": <path to exe>,
         "useWebView": true
      }

Could it be that I exited the process in an unexpected way leaving the WebView2 in a bad state?

Additional context
This definitely seems linked to the WebView2 runtime. If I uninstall WebView2 runtime and install Edge Canary (i.e. causing the WebView2 SDK to use the Canary runtime) then I do not get this exception.

If I re-install the WebView2 runtime (i.e. Evergreen) then the SDK will again try and use the Evergreen runtime and I will once again get the exception.

That is to say, an uninstall-then-reinstall of the runtime does not reset whatever state is causing this issue. Neither does a restart of my system.

My guess is that there's something in the registry/COM component on my system that is holding some bad state that is not allowing me to initialize a CoreWebView2 instance against the Evergreen runtime, but I have no idea how I can clear all the state involved if uninstalling doesn't even do it.

@christopherbadman christopherbadman added the bug Something isn't working label Sep 29, 2021
@drocx
Copy link

drocx commented Sep 29, 2021

I have got the same Problem:

Windows 10
Winforms Project
WebView2 Version 1.0.992.28
Evegreen Version 94.0.992.31
Errormessage: WebView2 was already initialized with a different CoreWebView2Environment. Check to see if the Source property was already set or EnsureCoreWebView2Async was previously called with different values.

If i downgrade to 1.0.961.33 everthing works fine.

@rozeboosje
Copy link

yes me too

@JooJooBee666
Copy link

I'm seeing a similar issue in my WPF project. Only started with the update to 1.0.992.28 runtime but my await EnsureCoreWebView2Async never completes and in the console logs in Visual Studio I see "Exception thrown: 'System.ArgumentException' in Microsoft.Web.WebView2.Wpf.dll". I rolled back to 1.0.961.33 and the issue is gone again. I wouldn't call this latest update "stable". 😛

@rozeboosje
Copy link

rozeboosje commented Sep 29, 2021

Aha.....

"my await EnsureCoreWebView2Async never completes"

I think there is the problem.

My code contains an initialisation for the web browser:

    Dim oEnvironment As Microsoft.Web.WebView2.Core.CoreWebView2Environment
    oEnvironment = Await Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(browserExecutableFolder:=Nothing, userDataFolder:=System.IO.Path.GetTempPath(), options:=Nothing)
    Await oWB.EnsureCoreWebView2Async(environment:=oEnvironment)

When I take that out it starts working again with 1.0.992.28

@rozeboosje
Copy link

In fact it starts working again when I replace all the above with

  Await oWB.EnsureCoreWebView2Async

(without setting an Environment)

@christopherbadman
Copy link
Author

@drocx It looks like our error messages are different, so I'm not sure it's the exact same problem. I've also tried downgrading/upgrading SDKs without success. Also, other devs working on my project have the same pairing of runtime/SDK without issue, so that's why I'm led to believe there's some state hanging around on my machine causing the issue.

@rozeboosje My code is not passing in a CoreWebView2Environment instance to the EnsureCoreWebView2Async() call, so I think our issues are different.

@JooJooBee666
Copy link

JooJooBee666 commented Sep 29, 2021

@rozeboosje My code is not passing in a CoreWebView2Environment instance to the EnsureCoreWebView2Async() call, so I think our issues are different.

Mine is:

var env = await CoreWebView2Environment.CreateAsync(userDataFolder: "C:\Some\Path");
await WebView.EnsureCoreWebView2Async(env);
Debug.WriteLine("WebView2 Runtime version: " + WebView.CoreWebView2.Environment.BrowserVersionString);
WebView.CoreWebView2.Settings.IsPasswordAutosaveEnabled = true;
WebView.NavigationStarting += NavigationStarting;
WebView.NavigationCompleted += NavigationCompleted;

None of the code after the await fires. So the await never completes. Period. No matter what I do. The EnsureCoreWebView2Async method is completely broken as even passing null to it causes the error in the output logs and code to fail. Please remove 1.0.992.28 so other people don't get screwed over by this as well. Wait until it's actually stable and release a newer version.

UPDATE: I was wrong. Updated to reflect this

@rozeboosje
Copy link

It was all working so well until I tried to use the WebView2 in an Outlook Addin. In the Outlook Addin I cannot get it to work. It actually pops up message boxes:

"Microsoft Edge can't read and write to its data directory:
C:\Program Files\Microsoft Office\root\Office16\OUTLOOK.EXE.WebView2\EBWebView"

So I'm completely snookered on this issue

Yes this needs to be fixed :(

@rozeboosje
Copy link

rozeboosje commented Sep 29, 2021

However..... when I go and give myself sufficient permissions to "C:\Program Files\Microsoft Office\root\Office16\OUTLOOK.EXE.WebView2" it works again.

What I can't seem to be able to do is use my own "data directory" due to the software no longer allowing you to set and use your own environment. I obviously can't go telling all my customers they need to go and manually set permissions to a folder like the above.

@champnic
Copy link
Member

champnic commented Oct 5, 2021

Hey all - seems like a few separate issues are listed in this thread. I'll try to address them:

@christopherbadman - It does seem like something got wedged here. If you restart your machine does that resolve the issue? If not, I'll open this as a bug on our backlog and we can take a closer look. It's also possible that you are hitting a crash or hang that's present in the current runtime (version 94) that's fixed in the current Canary (version 96), although the fact that others aren't hitting this with the same setup suggests this isn't the case.

@drocx (and maybe @JooJooBee666) You are getting this error because you are trying to initialize twice with potentially different values, and so one of those initializations is doing nothing. That's what the error is warning about. You can find and fix the cause (multiple initialization) or you can catch and ignore the error. This error is a By Design change in behavior with the new SDK, and is specifically designed to help devs find issues in their code, the most common of which is initializing the control by setting the Source property, then trying to initialize after with EnsureCoreWebView2Async and a specific environment that just gets ignored, causing other errors or unexpected behavior.

@rozeboosje For an office addin you need to specify a location for the user data folder (UDF). By default the UDF gets created next to the app exe, which for an office addin is in C:\Program Files\Microsoft Office..., where the browser processes don't have write access. You can read more here: https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/user-data-folder
We are planning to improve the default UDF creation here: #1410

@champnic champnic self-assigned this Oct 5, 2021
@rozeboosje
Copy link

hello @champnic

Yes - that's what I originally did; see my comment from 6 days ago.

    Dim oEnvironment As Microsoft.Web.WebView2.Core.CoreWebView2Environment
    oEnvironment = Await Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(browserExecutableFolder:=Nothing, userDataFolder:=System.IO.Path.GetTempPath(), options:=Nothing)
    Await oWB.EnsureCoreWebView2Async(environment:=oEnvironment)

But this started throwing errors. In my main applications I can make those go away by not setting an environment but as you point out here that doesn't work for Add-ins - but that leaves me stuck between a rock and a hard place. When I try to create an environment Await oWB.EnsureCoreWebView2Async(environment:=oEnvironment) fails, and when I don't create an environment I can't use it in an Add-in

@christopherbadman
Copy link
Author

@champnic A restart of my machine does not fix the issue, so there must be some state persisted somewhere (registry/elsewhere) that is causing the runtime to believe it is not suitable to create a CoreWebView2 instance.

Feel free to reach out if you want me to check anything on my system - it might be quite difficult to reproduce this state.

@JooJooBee666
Copy link

JooJooBee666 commented Oct 5, 2021

@drocx (and maybe @JooJooBee666) You are getting this error because you are trying to initialize twice with potentially different values, and so one of those initializations is doing nothing. That's what the error is warning about. You can find and fix the cause (multiple initialization) or you can catch and ignore the error. This error is a By Design change in behavior with the new SDK, and is specifically designed to help devs find issues in their code, the most common of which is initializing the control by setting the Source property, then trying to initialize after with EnsureCoreWebView2Async and a specific environment that just gets ignored, causing other errors or unexpected behavior.

I'm not sure what you mean. This is the FIRST instance of initializing it, unless I am misunderstanding. I removed await WebView.EnsureCoreWebView2Async(env); but then the following Debug.WriteLine("WebView2 Runtime version: " + WebView.CoreWebView2.Environment.BrowserVersionString); fails with a null reference. Therefor, it is CLEARLY not being initialized twice.

I'd love some guidance on how to properly initialize with a set user data path if this is wrong.

@JooJooBee666
Copy link

JooJooBee666 commented Oct 5, 2021

@drocx (and maybe @JooJooBee666) You are getting this error because you are trying to initialize twice with potentially different values, and so one of those initializations is doing nothing. That's what the error is warning about. You can find and fix the cause (multiple initialization) or you can catch and ignore the error. This error is a By Design change in behavior with the new SDK, and is specifically designed to help devs find issues in their code, the most common of which is initializing the control by setting the Source property, then trying to initialize after with EnsureCoreWebView2Async and a specific environment that just gets ignored, causing other errors or unexpected behavior.

I'm not sure what you mean. This is the FIRST instance of initializing it, unless I am misunderstanding. I removed await WebView.EnsureCoreWebView2Async(env); but then the following Debug.WriteLine("WebView2 Runtime version: " + WebView.CoreWebView2.Environment.BrowserVersionString); fails with a null reference. Therefor, it is CLEARLY not being initialized twice.

I'd love some guidance on how to properly initialize with a set user data path if this is wrong.

Full code of everything that is going on before this so you can see I am not initializing it any other place:

public MainWindow()
        {
            //Check for settings upgrade and upgrade if necessary
            if (Settings.Default.NeedsUpgrade)
            {
                Settings.Default.Upgrade();
                Settings.Default.NeedsUpgrade = false;
                Settings.Default.Save();
            }

            //Initialize Cache folder path for browser
            _cacheFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) +                               "\\MyApp\Cache";
            InitializeComponent();
            WebGrid.RowDefinitions[0].Height = new GridLength(0);
            WebGrid.RowDefinitions[2].Height = new GridLength(0);
            FindTextBox.AddHandler(TextBox.MouseLeftButtonDownEvent, new MouseButtonEventHandler(FindTextBox_MouseLeftButtonDown), true);
            _ctx = SynchronizationContext.Current;
            Application.Current.MainWindow.Title =
                "MyApp - " + Assembly.GetExecutingAssembly().GetName().Version.ToString();
            LoadPrefs();
            URLText.Text = _homeURL;
            //Initialize WebView2 view
            _ = InitializeAsync();
        }

        private async Task InitializeAsync()
        {
            Debug.WriteLine("InitializeAsync");
            
            var env = await CoreWebView2Environment.CreateAsync(userDataFolder: _cacheFolderPath);
            await WebView.EnsureCoreWebView2Async(env);
            Debug.WriteLine("WebView2 Runtime version: " + WebView.CoreWebView2.Environment.BrowserVersionString);
            WebView.CoreWebView2.Settings.IsPasswordAutosaveEnabled = true;
            WebView.NavigationStarting += NavigationStarting;
            WebView.NavigationCompleted += NavigationCompleted;
            WebView.CoreWebView2.DOMContentLoaded += CoreWebView2_DOMContentLoadedAsync;
            WebView.Source = new Uri(_homeURL);
        }

        private void LoadPrefs()
        {
            Application.Current.MainWindow.Top = Properties.Settings.Default.Top;
            Application.Current.MainWindow.Left = Properties.Settings.Default.Left;
            Application.Current.MainWindow.Height = Properties.Settings.Default.Height;
            Application.Current.MainWindow.Width = Properties.Settings.Default.Width;
            Application.Current.MainWindow.WindowState = Properties.Settings.Default.State;
            try
            {
                WebView.ZoomFactor = Properties.Settings.Default.Zoom;
            }
            catch (Exception)
            {
                WebView.ZoomFactor = 0;
            }
        }
}

@rozeboosje
Copy link

Ok well daaaaaayum..... I think I may have got it working for myself. WebView2 1.0.992.28

I was setting the environment in a location other than where I was navigating. I don't know exactly what the problem is yet. Maybe it involved a different Dispatcher, or something "funky" with threading, but if I don't do that, and I just set the environment immediately preceding where I need it first, it seems to be working:

            If moWBHTML5.CoreWebView2 Is Nothing Then
                Dim oEnvironment As Microsoft.Web.WebView2.Core.CoreWebView2Environment
                oEnvironment = Await Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(browserExecutableFolder:=String.Empty, userDataFolder:=System.IO.Path.GetTempPath(), options:=Nothing)
                Try
                    Await moWBHTML5.EnsureCoreWebView2Async(environment:=oEnvironment)
                Catch

                End Try
            End If

            'immediately followed by
            moWBHTML5.CoreWebView2.Navigate(.....

That seems to work for me and initial tests suggest that it will also work in an Outlook Add-in

If I find out more I'll let you know.

@rozeboosje
Copy link

spoke a bit too soon about the outlook add-in. I have two dialogs in that Add-in in which I use a WebView2

When I use Dialog1, the WebView2 loads the content
When I use Dialog1 again, it still loads the content
When I use Dialog2, it loads the content. At this point I thought everything was working fine.

Then I used Dialog1 again and it no longer loads the content.

Gaaaaarhhhhhh... but I'm hoping that now I'm looking at a minor issue. Will keep you posted.

@champnic
Copy link
Member

champnic commented Oct 5, 2021

@rozeboosje I've also listed some workarounds for the environment issues you may have been running into with 1.0.992.28 here:
#1781 (comment)

@JooJooBee666 It's the line above, the WebView.Source that's causing the issue. When you remove the Ensure call, the Source property starts the initialization, but it's async and doesn't finish before the subsequent call tries to use the WebView2 and fails. As noted in #1782, this is indeed a bug - setting the Source after it's been properly initialized should not cause this crash. The workaround is straightforward and linked it in the reply to rozeboosje.

WebView2.Source = <uri> -> WebView2.CoreWebView2.Navigate(<uriString>)

@rozeboosje
Copy link

Thanks @champnic I think I'm already in the process of implementing workaround number 1 but I think there is something a bit funky about the second dialog. They are indeed WPF dialogs but I already noticed that in Dialog number 2 the code that navigates is executed twice. So I'll do a bit more digging around.

@JooJooBee666
Copy link

The workaround is straightforward and linked it in the reply to rozeboosje.

WebView2.Source = <uri> -> WebView2.CoreWebView2.Navigate(<uriString>)

Got it, thanks. I didn't see that over on #1781. I swtiched to using CoreWebView2.Navigate() now and everything is working properly again.

@rozeboosje
Copy link

I have implemented all the various workarounds but I am still getting this error in build 1.0.1020.30

The situation is quite peculiar. I have two WPF dialogs that are presented from an Outlook Addin. Dialog number 1 always works. But Dialog number 2 is behaving very strangely. If I use Dialog number 2 first, it works. But once I use Dialog number 1, Dialog number 2 stops working. I'm at my wits' end.

@champnic
Copy link
Member

champnic commented Nov 3, 2021

@rozeboosje Is there a sample app you could share that reproduces the issue we can use to debug?

@rozeboosje
Copy link

No.... it's part of a much larger Outlook Add-in solution based on Add-in Express and it's working fine for me in other solutions using the same "Previewer" Project. However if someone would like to connect through Teams I'll be very happy to show you my code "in situ" by sharing my screens.

@rozeboosje
Copy link

Ok I think I have it.... maybe this is something you guys can investigate.

Dialog 1 and Dialog 2 are both WPF windows

Dialog 1 is loaded when the user clicks a button in a Pane in an Outlook Inspector window
Dialog 2 is loaded from a System.Windows.Forms.Timer tick. The timer is activated from the main Add-in Module

So I suspect that the Outlook Inspector window is not presented through the main UI thread, and this is ultimately the cause of all my problems. To check this, I modified the code in the same "Tick" handler for the System.Windows.Forms.Timer that shows Dialog 2, and I show Dialog 1 in that Tick event. When I do that, the "Preview" that hosts the WebView2 control in Dialog 1 always works even after I show Dialog 2

@champnic
Copy link
Member

champnic commented Nov 3, 2021

Ah, yes this may be a threading issue:
https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/threading-model

You may also look into using a dispatcher to have Dialog 2 open on the same thread that Dialog 1 did.

@rozeboosje
Copy link

Yes my biggest problem is that Outlook itself isn't a WPF application so I don't have an application.current.dispatcher available. But I guess I could create one when the startup for the addin completes and then always use that .... hm.... ok I'll give that a try tomorrow.

@rozeboosje
Copy link

Hello @champnic

That was it! I introduced a dummy window in my WPF DLL. Merely creating a shared (static) instance of it when the Add-in's Startup has completed is sufficient for it to make a Dispatcher available to me. It never needs to be shown. Using theInstance.Dispatcher.Invoke() to show the various other dialogs made my problem go away

Ok. Having said that..... Would it not be possible to make the WebView2 control less sensitive to such threading issues? Providing a mechanism to, say, create two separate WebView2 controls each with their own Environment that won't interfere with each other? What, for example, will happen if another party develops an Outlook Add-in that uses WebView2? Could their implementation cause ours to fail or vice versa?

@rozeboosje
Copy link

Also - just to satisfy my curiosity here.... Would the old WebBrowser control have had similar issues?

@champnic
Copy link
Member

champnic commented Nov 4, 2021

@rozeboosje Glad you got it working!

Would it not be possible to make the WebView2 control less sensitive to such threading issues?

In theory, each WebView2 should only be single-threaded for itself. You should be able to have multiple-threads each with it's own WebView2 control, as long as they are only accessed from the thread they were created on.

I'm actually wondering in this case if the problem was that the System.Windows.Forms.Timer thread wasn't setup to display a WebView2 (not a Single Threaded Apartment thread with a message pump, for example). The remarks here also indicate that using the System.Timers might be better suited in this scenario:
https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.timer?view=windowsdesktop-5.0#remarks

@champnic
Copy link
Member

champnic commented Nov 4, 2021

Also - just to satisfy my curiosity here.... Would the old WebBrowser control have had similar issues?

I'm not sure - I only joined the team during WebView2 so I'm not super familiar with the WebBrowser threading model. @bradp0721 do you happen to know the answer?

@champnic
Copy link
Member

champnic commented Jun 2, 2023

Closing old issue. Please let me know if we need to re-open this for any reason. Thanks!

@champnic champnic closed this as not planned Won't fix, can't repro, duplicate, stale Jun 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants