我一直在试图找出这个问题。我正在使用一个读入动态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
以外的功能。
如果有人能帮助我,我会非常感激,因为我已经花了整整一个上午试图围绕这个问题。
答案 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()
将结果直接返回给调用者会更有意义。如果以这种方式编写代码,线程同步的问题就会更加明显,因为您可能已经注意到在该值实际可用之前返回的方法。
但是如果你坚持使用异步方法,上面的改变至少应该解决你的线程同步问题。