WebView2Feedback icon indicating copy to clipboard operation
WebView2Feedback copied to clipboard

Unable to cast to Microsoft.Web.WebView2.Core.Raw.ICoreWebView2Cookie

Open WildlifeSOS opened this issue 3 years ago • 18 comments

I am using Visual Studio 2019 with a VB.Net application and DLLs that target .NET Framework 4.8 These components use the WebBrowser control and I'm now trying to convert it to use the WebView2 control I have installed the Canary Channel MicrosoftEdgeSetupCanary.exe file version 1.3.153.53 and I'm using NuGet WebView2 version 1.0.1054.31 Currently I'm trying to use WebView21.CoreWebView2.CookieManager.GetCookiesAsync(m_loginHandler.BaseUrlPath) to retrieve the cookies that the WebBrowser control used to give me. The List(Of CoreWebView2Cookie) returned has 1 item in it but when I try and access the cookie name & value I get

System.NotImplementedException
  HResult=0x80004001
  Message=Unable to cast to Microsoft.Web.WebView2.Core.Raw.ICoreWebView2Cookie.
This may happen if you are using an interface not supported by the version of the WebView2 Runtime you are using.
For instance, if you are using an experimental interface from an older SDK that has been modified or removed in a newer runtime.
Or, if you are using a public interface from a newer SDK that wasn't implemented in an older runtime.
For more information about WebView2 versioning please visit the following: https://docs.microsoft.com/microsoft-edge/webview2/concepts/versioning
  Source=Microsoft.Web.WebView2.Core
  StackTrace:
   at Microsoft.Web.WebView2.Core.CoreWebView2Cookie.get__nativeICoreWebView2Cookie()
   at Microsoft.Web.WebView2.Core.CoreWebView2Cookie.get_Name()
   at Thunderhead.Web.LoginHandler.UpdateCookies(CookieCollection httpCookies) in C:\source.net\WebView\VB.NET\ThWeb\Login\LoginHandler.vb:line 237

I'm trying the following approach to get the html source and the cookies; the html source comes back perfectly.

        Private WithEvents m_htmlSourceTimer As Timers.Timer
        Private m_htmlSourceTask As Threading.Tasks.Task(Of String)
        Private m_htmlSource As String

        Private WithEvents m_getCookiesTimer As Timers.Timer
        Private m_getCookiesTask As Threading.Tasks.Task(Of List(Of CoreWebView2Cookie))

        Private WithEvents m_metaDataCheckTimer As Timers.Timer

        Private Sub NavigationCompleted(ByVal sender As Object, ByVal e As EventArgs)
            EnableTimers()
        End Sub
		
        Private Sub EnableTimers()
            If m_domContentedLoaded Then
                If m_htmlSourceTimer Is Nothing Then
                    m_htmlSourceTimer = NewTimer()
                End If
                If Not m_htmlSourceTimer.Enabled Then
                    m_htmlSourceTask = WebView21.CoreWebView2.ExecuteScriptAsync("document.documentElement.outerHTML;")
                    m_htmlSourceTimer.Start()
                End If
                If m_getCookiesTimer Is Nothing Then
                    m_getCookiesTimer = NewTimer()
                End If
                If Not m_getCookiesTimer.Enabled Then
                    m_getCookiesTask = WebView21.CoreWebView2.CookieManager.GetCookiesAsync(m_loginHandler.BaseUrlPath)
                    m_getCookiesTimer.Start()
                End If
            End If
        End Sub

        Private Function NewTimer() As Timers.Timer
            Dim result As New Timers.Timer
            result.Interval = 250
            result.AutoReset = True
            Return result
        End Function

        Private Sub CookieAndHtmlSourceTimerElapsed(ByVal sender As Object, ByVal e As EventArgs) Handles m_htmlSourceTimer.Elapsed, m_getCookiesTimer.Elapsed
            If m_htmlSourceTask.IsCompleted Then
                m_htmlSourceTimer.Stop()
                m_htmlSource = WebView2Helper.WebViewHTML(m_htmlSourceTask.Result)
            End If
            If m_getCookiesTask.IsCompleted Then
                m_getCookiesTimer.Stop()
                m_loginHandler.WebView2Cookies = m_getCookiesTask.Result
            End If
            If m_htmlSourceTask.IsCompleted AndAlso m_getCookiesTask.IsCompleted Then
                If m_metaDataCheckTimer Is Nothing Then
                    m_metaDataCheckTimer = NewTimer()
                End If
                If Not m_metaDataCheckTimer.Enabled Then
                    m_metaDataCheckTimer.Start()
                End If
            End If
        End Sub

        Private Sub MetaDataCheckTimerElapsed(ByVal sender As Object, ByVal e As EventArgs) Handles m_metaDataCheckTimer.Elapsed
            m_metaDataCheckTimer.Stop()
            CheckForSalesforceLogin()
            CheckForToken()
        End Sub

I have a couple of questions

  1. Should I be using WebView21.CoreWebView2.CookieManager.GetCookiesAsync?
  2. If so, what am I doing wrong?

AB#37255788

WildlifeSOS avatar Nov 30 '21 17:11 WildlifeSOS

I've checked that I'm using the latest Canary version and I think that I am. I've also tried to use the NuGet WebView2 1.0.1083-prerelease and that has the same problem

WildlifeSOS avatar Nov 30 '21 17:11 WildlifeSOS

Using the debugger the cookie shows up like this

CoreWebView2CookieError

WildlifeSOS avatar Nov 30 '21 17:11 WildlifeSOS

Hey @JimWard2018 - You can verify the version of the runtime that your app is using by looking at the command-line of the launched child msedgewebview2.exe process in Task Manager or Process Explorer, or by looking at CoreWebView2Environment.BrowserVersionString.

Are you following this guidance to make your app use the Canary runtime? If not, it's possible it's using a really old stable WebView2 runtime or something. https://docs.microsoft.com/en-us/microsoft-edge/webview2/how-to/set-preview-channel

I'm unfamiliar with the approach you took for waiting for the completion of the async handlers, but you'll want to make sure that when you try to access the cookies you are doing so on the same thread you created the WebView2 on. It's possible the timer function is being run on a background thread.

champnic avatar Dec 01 '21 01:12 champnic

  1. WebView21.CoreWebView2.Environment.BrowserVersionString is 98.0.1090.0 canary
  2. I have looked at that web page. I do not have the WebView evergreen runtime installed. According to https://www.nuget.org/packages/Microsoft.Web.WebView2 the latest prerelease is 1.0.1083-prerelease which I tried yesterday and that gave me the same problem as I said. I'm currently using the last stable build which is 1.0.1054.31. Both became available recently.

So is '98.0.1090.0 canary' compatible with WebView2 version 1.0.1054.31?

  1. It looks like I have a thread problem I introduced timers to get the html source of the loaded page. I was originally calling WebView21.CoreWebView2.ExecuteScriptAsync("document.documentElement.outerHTML;") in the NavigationCompleted event and that didn't work. It does work using a timer

WildlifeSOS avatar Dec 01 '21 13:12 WildlifeSOS

I've been experimenting calling

WebView21.CoreWebView2.ExecuteScriptAsync("document.documentElement.outerHTML;")

in timers and using pool tasks

Task.Run(Of String)(Function() WebView21.CoreWebView2.ExecuteScriptAsync("document.documentElement.outerHTML;"))

In pool tasks I always get errors like

System.InvalidOperationException HResult=0x80131509 Message=CoreWebView2 can only be accessed from the UI thread. Source=Microsoft.Web.WebView2.WinForms StackTrace: at Microsoft.Web.WebView2.WinForms.WebView2.get_CoreWebView2()

but in timers I don't; so I'm assuming that I the timers are running in the UI thread where the WebView2 control was created

However I'm still getting the same error I reported yesterday and I believe that I am retrieving the cookies on the same thread as the WebView2 control with my timer solution

WildlifeSOS avatar Dec 01 '21 16:12 WildlifeSOS

Thanks for the added info and confirmations! It might be worth trying to use a dispatcher to make sure the cookies are accessed from the WebView2 thread, but from what you've said above that seems unlikely to be the cause.

Looking at the screenshot, it also looks like you are saving the cookies list from the function into a separate variable, and then accessing it later. If you access the cookies right away when you get them, do you run into this error? I'm wondering if maybe the list of cookies is getting out of date.

champnic avatar Dec 01 '21 18:12 champnic

I get the same error if I access the cookies straightaway

CoreWebView2CookieError2

I don't understand what you mean by trying to use a dispatcher; could you elaborate?

WildlifeSOS avatar Dec 01 '21 20:12 WildlifeSOS

This is what I had in mind with the dispatcher, although I realize now it's WPF and you are using Winforms :/ https://docs.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatcher?view=windowsdesktop-6.0

champnic avatar Dec 01 '21 22:12 champnic

Thanks for your help so far Nic.

I did explore the dispatcher option. I've changed my solution slightly to use

`

WebView21.BeginInvoke(Sub() m_getCookiesTask = WebView2Helper.GetCookies(WebView21, WebView21.Source.AbsoluteUri))

WebView21.BeginInvoke(Sub() m_htmlSourceTask = WebView2Helper.GetHtmlSource(WebView21))

`

to ensure I'm using the WebView21 thread but I still get the SystemNotImplemented exception whenever I try and access any of the cookie properties returned by

WebView21 .CoreWebView2.CookieManager.GetCookiesAsync(uri)

I guess it's an issue that needs fixing

WildlifeSOS avatar Dec 02 '21 15:12 WildlifeSOS

Thanks for confirming. I've added this as a bug on our backlog. Have you also tried using "await"?

champnic avatar Dec 02 '21 23:12 champnic

Yes, the helper functions that I call use await already

`

Public Shared Async Function GetCookies(ByVal wv As Microsoft.Web.WebView2.WinForms.WebView2, ByVal uri As String) As Task(Of List(Of CoreWebView2Cookie))
    Return Await wv.CoreWebView2.CookieManager.GetCookiesAsync(uri)
End Function

Public Shared Async Function GetHtmlSource(ByVal wv As Microsoft.Web.WebView2.WinForms.WebView2) As Task(Of String)
    Return Await wv.CoreWebView2.ExecuteScriptAsync("document.documentElement.outerHTML;")
End Function

`

WildlifeSOS avatar Dec 03 '21 09:12 WildlifeSOS

Hi Nic,

Is there a bug reference number?

WildlifeSOS avatar Dec 03 '21 10:12 WildlifeSOS

We have an internal bug link that's been appended to your original post, but otherwise we'll use this GH issue to track and add updates.

champnic avatar Dec 03 '21 19:12 champnic

Hi @champnic Do you have any idea when this may be fixed? This is a show stopper for me now as I need those cookies for my application to log in.

WildlifeSOS avatar Feb 04 '22 09:02 WildlifeSOS

No timeline on this issue.

champnic avatar Feb 05 '22 00:02 champnic

Any updates? It seems I am facing the same problems with (Nuget) version 1.0.1938.49 inside a Windows Forms application.

WebView().ContinueWith(webViewTask =>
{
    var webView = webViewTask.Result;
    webView.Invoke(new Action(() =>
    {
        var cookieManager = webView.CoreWebView2.CookieManager;
        webView.CoreWebView2.CookieManager.GetCookiesAsync(null).ContinueWith(
            cookieListTask =>
            {
                var cookieList = cookieListTask.Result;
                foreach (var t in cookieList)
                {
                    Debug.WriteLine("Cookie: " + t.Domain + ", " + t.Name + ", " + t.Value);
                }
            }
        );
    }));
});

gives me

System.NotImplementedException: 'Unable to cast to Microsoft.Web.WebView2.Core.Raw.ICoreWebView2Cookie.
This may happen if you are using an interface not supported by the version of the WebView2 Runtime you are using.
For instance, if you are using an experimental interface from an older SDK that has been modified or removed in a newer runtime.
Or, if you are using a public interface from a newer SDK that wasn't implemented in an older runtime.
For more information about WebView2 versioning please visit the following: https://learn.microsoft.com/microsoft-edge/webview2/concepts/versioning'

Update: awaiting the list instead of using a ContinueWith works... but why?

WebView().ContinueWith(webViewTask =>
{
    var webView = webViewTask.Result;
    webView.Invoke(new Action(async () =>
    {
        var cookieList = await webView.CoreWebView2.CookieManager.GetCookiesAsync(null);
        foreach (var t in cookieList)
        {
            Debug.WriteLine("Cookie: " + t.Domain + ", " + t.Name + ", " + t.Value);
        }
    }));
});

WolfgangVogl avatar Sep 12 '23 13:09 WolfgangVogl

Found the issue after getting

Exception thrown: 'System.NotImplementedException' in Microsoft.Web.WebView2.Core.dll Unable to cast to Microsoft.Web.WebView2.Core.Raw.ICoreWebView2_2.

The fix is to make sure you call whatever CoreWebView2 methods on the UI thread.

vborovikov avatar Dec 17 '23 18:12 vborovikov

Just ran into the same issue. Would be more than nice, if the control would just throw an exception that the access is not done on the UI thread, to avoid looking for other sources for the error...

obartelt avatar Feb 28 '24 08:02 obartelt