C# WebClient和线程管理出现问题

C# WebClient和线程管理出现问题,c#,multithreading,asynchronous,webclient,C#,Multithreading,Asynchronous,Webclient,我一直在绞尽脑汁想弄明白这个问题。我使用的是一个WebClient控件,可以读取动态URL。我试图提取的一些数据在从服务器检索时不在HTML源代码中,但在以后使用Javascript/AJAX呈现 我使用了多种方法,包括Thread.Join()和BackgroundWorker,结果为零 我现在尝试使用async方法,但老实说,我完全不知道我在做什么 这是我的密码: protected void retrieveDataSource(int matchId_val) { ManualReset

我一直在绞尽脑汁想弄明白这个问题。我使用的是一个WebClient控件,可以读取动态URL。我试图提取的一些数据在从服务器检索时不在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)
时,我得到一个空异常应该注意如果我点击“继续”,那么断点将到达
DownloadStringCompleted
函数,这是我无法理解的


如果有人能帮助我,我将不胜感激,因为我已经花了整整一个上午的时间来思考这个问题。

在尝试这一点时,您可能最终会遇到一些困难。底线是,要获取动态生成的内容,必须呈现页面,这与下载HTTP服务器为给定URL提供的内容有很大不同

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

总而言之,代码中有一个非常明显的bug。您创建了一个事件句柄,它显然是用来发出异步操作完成的信号,但您从不等待它。这意味着启动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()
直接将结果返回给调用者更有意义。如果代码是以这种方式编写的,那么线程同步的问题就会更加明显,因为您可能已经注意到该方法在该值实际可用之前返回


但是,如果您坚持使用异步方法,上述更改至少可以解决您的线程同步问题。

在您尝试获取源中不存在的数据时,您无法检索该数据。您需要知道页面正在使用的AJAX源代码,并直接调用它,就像要访问数据的页面一样。假设AJAX源代码的所有者允许这样做。我可以使用
Thread.Join()
成功地提取数据,但会遇到MemoryException或
线程。Join
会永久挂起。在无限期挂起之前,只有2-3个条目是非常低效的,但至少我知道有一种方法可以在不知道AJAX源代码的情况下成功提取数据。首先,感谢您的回复。当我使用
DownloadString
时,我在
中查找的HTML元素会产生结果。使用
Thread.Join
Application.DoEvents()时
尽管有时会出现程序挂起或内存异常,但我至少能够访问导致
的HTML元素。此外,我还找到了用于呈现
的静态Javascript文件,该文件位于此处:不清楚“使用Thread.Join和Application.DoEvents()是什么意思。”,但在一个正确的、编写良好的实现中,两者都不是必需的。上面应该通过确保操作已完成来解决空引用问题,但它当然会阻止正在等待的线程,这可能会导致其他问题。如果不能清楚地显示代码的结构,恐怕只能提供不比上面更具体的建议。