Forum Discussion

Steve_PP's avatar
Steve_PP
Experienced User
4 months ago

C# WebBrowser -> WebView2 solution

Hi

 

Here is a solution for those with C#.NET apps that need to update the internal browser their desktop app invokes when OAuth is required due to breaking changes enforced by MYOB in Aug 2024. In summary, you need to replace WebBrowser with WebView2 (NuGet: Microsoft.Web.WebView2)

 

If you used the MYOB template of many years ago, you can replace OAuthLogin.GetAuthorizationCode with this:

 

        public static async Task<string> GetAuthorizationCode(IApiConfiguration config)
        {
            // Format the URL for the OAuth server login
            string url = string.Format("{0}?client_id={1}&redirect_uri={2}&scope={3}&response_type=code",
                                       CsOAuthServer, config.ClientId, HttpUtility.UrlEncode(config.RedirectUrl), CsOAuthScope);

            // Create a new form with WebView2
            var frm = new Form();
            var webView2 = new WebView2
            {
                Dock = DockStyle.Fill
            };
            frm.Controls.Add(webView2);

            // Set up a TaskCompletionSource to signal when the form can close
            var tcs = new TaskCompletionSource<string>();

            // Subscribe to NavigationCompleted to capture the OAuth redirect
            webView2.CoreWebView2InitializationCompleted += (sender, args) =>
            {
                if (args.IsSuccess)
                {
                    // Navigate to the OAuth login URL
                    webView2.CoreWebView2.Navigate(url);
                }
            };

            // Capture the URL in NavigationStarting
            webView2.NavigationStarting += (sender, args) =>
            {
                // Store the URI when navigation starts
                _currentUri = args.Uri;
            };

            // Use NavigationCompleted to check if the URI contains the authorization code
            webView2.NavigationCompleted += (sender, args) =>
            {
                if (_currentUri.Contains("code="))
                {
                    // Extract the authorization code from the URL
                    string code = ExtractAuthorizationCode(_currentUri);

                    // Signal the TaskCompletionSource that the form can close with the code
                    tcs.SetResult(code);

                    // Close the form
                    frm.Invoke((MethodInvoker)(() => frm.Close()));
                }
            };

            // Initialize WebView2 control asynchronously
            await webView2.EnsureCoreWebView2Async(null);

            frm.Size = new Size(800, 600);
            frm.Show();

            // Wait until the TaskCompletionSource is signaled (form is closed)
            string authCode = await tcs.Task;

            return authCode;

        }

 

Notes:

 

1. Change the call to the updated method to include an await:

_oAuthKeyService.OAuthResponse = oauthService.GetTokens(await   OAuthLogin.GetAuthorizationCode(_configurationCloud));

 

2. Make the containing method async

private async void Login()

 

3. You will probably get a brief flash of 'Failed navigation' as the http://desktop redirect page is shown before the form drops away. Maybe someone can sort that. Ironically, I don't need this code any more based on what I have been forced to learn this weekend.