WebClient和线程管理问题

时间:2015-06-23 15:09:34

标签: c# multithreading asynchronous webclient

我一直在试图找出这个问题。我正在使用一个读入动态URL的WebClient控件。我试图提取的数据在从服务器检索时不在HTML源代码中,但稍后使用Javascript / AJAX进行呈现。

我使用了多种方法,包括Thread.Join()BackgroundWorker,结果为零。

我现在正在尝试使用async方法,但说实话,我完全迷失了我正在做的事情。

这是我的代码:

protected void retrieveDataSource(int matchId_val)
{
ManualResetEvent completionEvent = new ManualResetEvent(false);
WebClient wc = new WebClient();
wc.DownloadStringCompleted += delegate(object sender, DownloadStringCompletedEventArgs e)
{
source = e.Result;
completionEvent.Set();
};
wc.DownloadStringAsync(new Uri("http://na.lolesports.com/tourney/match/" + matchId_val));
}

protected void LoadWebPage()
{
retrieveDataSource(matchId_val);
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(source);
}

source是一个全局变量,最初设置为null。当我运行此代码时,DownloadStringCompleted参数永远不会被触发,因此源永远不会从null更改。当它达到doc.LoadHtml(source)时,我被赋予了一个空例外。 IT应该注意,如果我点击“继续”,那么断点将到达DownloadStringCompleted以外的功能。

如果有人能帮助我,我会非常感激,因为我已经花了整整一个上午试图围绕这个问题。

1 个答案:

答案 0 :(得分:2)

当您尝试这种方法时,最终会遇到许多困难。最重要的是,为了获得动态生成的内容,您必须呈现页面,这与简单地下载HTTP服务器为给定URL提供的内容有很大不同。

此外,还不清楚您使用什么来呈现网页。您正在使用名为HtmlDocument的类和名为LoadHtml()的方法。这表明你正在使用Html Agility Pack,但你的问题在这一点上是沉默的。我的回忆是,该库不呈现HTML;但我可能是错的或者有过时的信息。

所有这一切,你的代码中都有一个非常明显的错误。您创建了一个事件句柄,它显然用于表示异步操作的完成,但您永远不会等待它。这意味着启动I / O的线程将继续运行并尝试在实际可用之前检索结果。

解决这个问题的一种方法是等待事件句柄:

protected void retrieveDataSource(int matchId_val)
{
    ManualResetEvent completionEvent = new ManualResetEvent(false);
    WebClient wc = new WebClient();
    wc.DownloadStringCompleted += delegate(object sender, DownloadStringCompletedEventArgs e)
    {
        source = e.Result;
        completionEvent.Set();
    };
    wc.DownloadStringAsync(new Uri("http://na.lolesports.com/tourney/match/" + matchId_val));
    completionEvent.WaitOne();
}

当然,如果您在等待操作完成时只是要创建线程块,那么就会出现为什么要使用异步I / O的问题?为什么不直接调用DownloadString(),这将自动阻止,直到操作完成。

我还建议不要使用类字段来将数据从被调用的方法传递给调用者。这里retrieveDataSource()将结果直接返回给调用者会更有意义。如果以这种方式编写代码,线程同步的问题就会更加明显,因为您可能已经注意到在该值实际可用之前返回的方法。

但是如果你坚持使用异步方法,上面的改变至少应该解决你的线程同步问题。