处理WebBrowser控件会导致在系统浏览器中打开新页面

时间:2014-03-31 04:20:18

标签: c# wpf winforms wpf-controls webbrowser-control

问题是我previous question的延续。问题的简短解释:我试图在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浏览器不包含有效的会话数据。丢弃会话可以转到设置 - >您网页的安全性 - >看活动的历史 - >关闭所有会议

mainForm代码:

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);
    }
}

authenticationForm代码:

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);
    }
}

here is full project code

1 个答案:

答案 0 :(得分:0)

我也遇到了与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;
}