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.