我在C#,4.0中使用WebClient类。我需要使用30,000个不同的ID来访问REST服务,并获取状态结果(200或404)。以下是进行调用的方法(eventCounter是CountdownEvent对象):
private void doWork()
{
initDB();
List<string> _lines = new List<string>();
//pull all UpcIds into a List
using (StreamReader _rdr = new StreamReader(@"C:\Users\kkohut\Dropbox\ROVI\Application Support\BestBuy\upc_test2.txt"))
{
string _line;
while ((_line = _rdr.ReadLine()) != null)
{
_lines.Add(_line);
}
}
numIds = _lines.Count();
for (int i = 0; i < numIds; i++)
{
string _upcId = _lines[i];
WebClient c = new WebClient();
c.DownloadDataCompleted += new DownloadDataCompletedEventHandler(c_DownloadDataCompleted);
c.DownloadDataAsync(new Uri(BASE_URL + _upcId), _upcId);
}
//this is not working correctly. Code execution hits this line and waits, without processing any of the
//the DownloadDataCompleted eventhandlers
eventCounter.Wait();
}
这是DownloadDataCompleted事件处理程序
void c_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
DataSet _ds = new DataSet();
string _upcId = e.UserState.ToString();
string _status = "404";
try
{
if (!e.Cancelled && e.Error == null)
{
string _result = System.Text.Encoding.UTF8.GetString(e.Result);
if (_result.IndexOf("<code>200</code>") > 0)
{
_status = "200";
}
}
}
catch (Exception ex)
{
_status = "404";
}
finally
{
updateDB(_upcId, _status);
eventCounter.Signal(1);
txtLog.Text += string.Format("{0}\t{1}\t{2}\r\n",ctr, _upcId, _status);
}
}
如果我注释掉eventCounter.Wait()语句,则调用有效,但我无法知道它们何时完成。这是一个winforms应用程序,所以只要我保持表单运行,所有调用都会完成。但是,如果我取消注释eventCounter.Wait()语句,则不会处理任何调用。似乎Wait()语句阻止异步调用开始。我发现的每个例子都使用这种方法,但它们都没有在完成的事件处理程序中用信号通知CountdownEvent。想法?
答案 0 :(得分:2)
WebClient Class实现Event-based Asynchronous Pattern (EAP)。
在此模式中,XXXAsync方法captures current SynchronizationContext(即WPF或WinForms应用程序中的UI线程)。操作完成后,将在此上下文中执行事件处理程序。
(另见:On which thread(s) does WebClient raise its events?)
问题:如果在UI线程上调用阻塞方法,则在阻塞方法返回之前,事件处理程序将不会运行。
解决方案:异步等待CountdownEvent完成,而不是同步。
您可以使用ThreadPool.RegisterWaitForSingleObject Method为WaitHandle的CountdownEvent注册回调。