webview_csharp icon indicating copy to clipboard operation
webview_csharp copied to clipboard

Call to SharpWebview.Webview.Navigate fails on call to SingleOrDefault

Open NickHarvey2 opened this issue 1 year ago • 2 comments

When calling the Navigate method at application startup, GetWebViewAppContainerSid seems to find more than one AppContainer with a name matching microsoft.win32webviewhost_cw5n1h2txyewy, resulting in this error (this stacktrace is from the example DesktopApp, but the same happens with my own app)

~\webview_csharp\examples\DesktopApp> dotnet run
Unhandled exception. System.InvalidOperationException: Sequence contains more than one matching element
   at System.Linq.ThrowHelper.ThrowMoreThanOneMatchException()
   at System.Linq.Enumerable.TryGetSingle[TSource](IEnumerable`1 source, Func`2 predicate, Boolean& found)
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
   at SharpWebview.Loopback.GetWebViewAppContainerSid() in ~\webview_csharp\src\SharpWebview\Loopback.cs:line 31
   at SharpWebview.Loopback.IsWebViewLoopbackEnabled() in ~\webview_csharp\src\SharpWebview\Loopback.cs:line 21
   at SharpWebview.Webview.CheckLoopbackException(String url) in ~\webview_csharp\src\SharpWebview\Webview.cs:line 260
   at SharpWebview.Webview.Navigate(IWebviewContent webviewContent) in ~\webview_csharp\src\SharpWebview\Webview.cs:line 94
   at DesktopApp.Program.Main(String[] args) in ~\webview_csharp\examples\DesktopApp\Program.cs:line 24

I have checked that I added the loopback exemption

> CheckNetIsolation.exe LoopbackExempt -s

List Loopback Exempted AppContainers

[1] -----------------------------------------------------------------
    Name: AppContainer NOT FOUND
    SID:  S-1-15-2-490905099-2794809881-2632752266-3514030558-4166392763-3416490339-321513134

[2] -----------------------------------------------------------------
    Name: microsoft.win32webviewhost_cw5n1h2txyewy
    SID:  S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646

OK.

(I actually tried clearing and re-adding the exemption a couple of times to no avail, because apparently the exemption list can become corrupted)

This is on Windows 11 21H2, using .NET 6.0.8 (SDK 6.0.400), WebView2 Runtime 105.0.1343.27

NickHarvey2 avatar Sep 07 '22 23:09 NickHarvey2

I did some console.log debugging in my local clone to log out the properties of the multiple matching AppContainers, and saw this:

displayName:       @{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}
appContainerName:  Microsoft.Win32WebViewHost_cw5n1h2txyewy
packageFullName:   Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy
workingDirectory:  C:\Windows\SystemApps\Microsoft.Win32WebViewHost_cw5n1h2txyewy\
appContainerSid:   1867581628288
description:       @{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}

displayName:       @{Microsoft.Win32WebViewHost_10.0.19041.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}
appContainerName:  microsoft.win32webviewhost_cw5n1h2txyewy
packageFullName:   Microsoft.Win32WebViewHost_10.0.19041.1_neutral_neutral_cw5n1h2txyewy
workingDirectory:  C:\Windows\SystemApps\Microsoft.Win32WebViewHost_cw5n1h2txyewy\
appContainerSid:   1867581635808
description:       @{Microsoft.Win32WebViewHost_10.0.19041.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}

Noticed one of the appContainerNames is all lowercase and the other is mixed case, I removed the ToLower call when matching by name, and then the app appears to have run correctly. Then I changed the value of WebViewAppContainerName to match the mixed case appContainerName, and it also worked.

I'm new to Webview so a lot of this is beyond me and certainly don't know this well enough for a PR, but hopefully that is helpful? I'll keep looking at it, and if I learn enough to actually contribute a meaningful fix I'll submit a PR.

NickHarvey2 avatar Sep 07 '22 23:09 NickHarvey2

Okay, this may be simpler to fix than I thought. It seems like the Loopback class's only public method is there to check if the loopback is allowed before proceeding, if so I think the following would work (I'll submit a PR shortly)

         public bool IsWebViewLoopbackEnabled()
         {
-            var webViewSid = GetWebViewAppContainerSid();
+            var webViewSids = GetWebViewAppContainerSids();
             return GetAllAppContainerConfigs().Any(c =>
             {
                 ConvertSidToStringSid(c.Sid, out var currentSid);
-                return currentSid == webViewSid;
+                return webViewSids.Any(webViewSid => currentSid == webViewSid);
             });
         }

-        private string GetWebViewAppContainerSid()
+        private IEnumerable<string> GetWebViewAppContainerSids()
         {
-            var webviewAppContainer = GetAllAppContainers()
-                .SingleOrDefault(a => a.appContainerName.ToLower() == WebViewAppContainerName);
-            ConvertSidToStringSid(webviewAppContainer.appContainerSid, out var webViewSid);
-            return webViewSid;
+            return GetAllAppContainers()
+                .Where(a => a.appContainerName.ToLower() == WebViewAppContainerName)
+                .Select(firewallAppContainer => {
+                    ConvertSidToStringSid(firewallAppContainer.appContainerSid, out var webViewSid);
+                    return webViewSid;
+                });
         }

NickHarvey2 avatar Sep 09 '22 02:09 NickHarvey2