释放 Web 浏览器控件会导致在系统浏览器中打开新页面
本文关键字:浏览器 系统 新页面 Web 控件 释放 | 更新日期: 2023-09-27 17:55:24
问题是我上一个问题的延续。问题的简短解释:我尝试在WinForms应用程序中使用WebBrowser vk.com 使用类似OAuth2的方法授权用户,因此我需要在WebBrowser中打开特定于应用程序的URL,vk.com 将重定向到授权页面。授权后,vk.com 重定向到https://oauth.vk.com/blank.html#access_token={accessToken}&expires_in={expiresIn}&user_id={userId}
,我可以在其中获取令牌并将其与 vk.com API 一起使用。一切都很好,除了在授权后的不同时间在浏览器中打开的奇数页面(带有 url https://oauth.vk.com/blank.html#access_token={accessToken}&expires_in={expiresIn}&user_id={userId}%20-%20#access_token={accessToken}&expires_in={expiresIn}&user_id={userId}
)。我有点重新设计了示例,现在如果在处理 WebBrowwser(AuthenticationForm -> authenticationBrowser_DocumentCompleted)控件后出现GC.WaitForPendingFinalizers(); GC.Collect();
,则页面无法在系统浏览器中打开,并在另一种情况下打开。
重要提示:仅当必须填写授权表单(即 Web 浏览器不包含有效的会话数据)时,该错误才会显现出来。 丢弃会话可以转到设置 ->页面的安全性 ->查看活动历史记录->关闭所有会话
主窗体代码:
public partial class Form1 : Form
{
private string _token;
private readonly Uri _redirectUri = new Uri("https://oauth.vk.com/blank.html");
private readonly Uri _request = new Uri("https://api.vk.com/method/users.get.xml?user_ids=1&fields=online");
private readonly Uri _authorizationUri =
new Uri("https://oauth.vk.com/authorize?client_id=3836576&scope=8&redirect_uri=https://oauth.vk.com/blank.html&display=page&response_type=token");
public Form1()
{
InitializeComponent();
}
private async void loginButton_Click(object sender, EventArgs e)
{
var authenticationForm = new AuthenticationForm();
authenticationForm.Show();
_token = await Authenticate(authenticationForm.GetToken);
authenticationForm.Close();
}
private async Task<string> Authenticate(Func<Uri, Uri, Task<string>> aunthenticationResultGetter)
{
var token = await aunthenticationResultGetter(_authorizationUri, _redirectUri);
//...
return token;
}
private async void doRequestButton_Click(object sender, EventArgs e)
{
//assume, we using token here
var httpClient = new HttpClient();
var response = await httpClient.GetAsync(_request);
var responseString = await response.Content.ReadAsStringAsync();
outputTextBox.AppendText(responseString);
}
}
认证表单代码:
public partial class AuthenticationForm : Form
{
private readonly TaskCompletionSource<string> _tokenCompletitionSource = new TaskCompletionSource<string>();
private Uri _redirectUri;
private WebBrowser _authenticationBrowser;
public AuthenticationForm()
{
InitializeComponent();
}
public async Task<string> GetToken(Uri authUri, Uri redirectUri)
{
_redirectUri = redirectUri;
_authenticationBrowser = new WebBrowser
{
Dock = DockStyle.Fill,
Location = new System.Drawing.Point(0, 0),
MinimumSize = new System.Drawing.Size(20, 20),
Name = "authenticationBrowser",
ScriptErrorsSuppressed = true,
Size = new System.Drawing.Size(641, 353),
TabIndex = 0
};
_authenticationBrowser.DocumentCompleted += authenticationBrowser_DocumentCompleted;
_authenticationBrowser.Navigate(authUri);
Controls.Add(_authenticationBrowser);
var token = await _tokenCompletitionSource.Task;
return token;
}
private void authenticationBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (!(_redirectUri.IsBaseOf(e.Url) && _redirectUri.AbsolutePath.Equals(e.Url.AbsolutePath))) return;
_authenticationBrowser.Dispose();
//GC.WaitForPendingFinalizers();
//GC.Collect();
var token = e.Url.ToString().Split('=')[1].Split('&')[0];
_tokenCompletitionSource.SetResult(token);
}
}
这是完整的项目代码
我在将 box.com api OAuth 集成到我的 WPF 应用程序中时也遇到了类似的问题。但是 box.com API 提供的 WPF 示例可以正常工作。
即使我更改了官方示例的逻辑和流程以与我的 WPF 应用程序匹配,我也无法重现该问题。
最后,我通过在导航事件中添加"about:blank"导航来解决此问题,如下所示,我正在共享代码,以便它可以帮助某人。
private void browserAuthentication_Navigating(object sender, NavigatingCancelEventArgs e)
{
if(e.Uri.Host.Equals( _callbackUri.Host))
{
e.Cancel = true;
//This code is required. Otherwise the box api navigation will popup an external browser window.
browserAuthentication.Navigate("about:blank");
this._authenticationResponseValues = GetQueryOptions(e.Uri);
}
}
private IDictionary<string, string> GetQueryStringParamAndValues(Uri resultUri)
{
string[] queryParams = null;
var queryValues = new Dictionary<string, string>();
int fragmentIndex = resultUri.AbsoluteUri.IndexOf("#", StringComparison.Ordinal);
if (fragmentIndex > 0 && fragmentIndex < resultUri.AbsoluteUri.Length + 1)
{
queryParams = resultUri.AbsoluteUri.Substring(fragmentIndex + 1).Split('&');
}
else if (fragmentIndex < 0)
{
if (!string.IsNullOrEmpty(resultUri.Query))
{
queryParams = resultUri.Query.TrimStart('?').Split('&');
}
}
if (queryParams != null)
{
foreach (var param in queryParams)
{
if (!string.IsNullOrEmpty(param))
{
string[] kvp = param.Split('=');
queryValues.Add(kvp[0], System.Net.WebUtility.UrlDecode(kvp[1]));
}
}
}
return queryValues;
}