区分多个web客户端结果
本文关键字:客户端 结果 web | 更新日期: 2023-09-27 17:50:16
有一个List
我想通过web客户端下载每个url。DownloadStringAsync
遇到的问题是:我怎么知道哪个e.Result对应哪个url ?
public class ressource{
public string url { get; set; }
public string result { get; set; }
}
List<ressource> urlist = new List<ressource>();
urlist.Add(new ressource(){url="blabla", result=string.empty});
....etc
var wc= new WebClient();
foreach(var item in urlist)
{
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
wc.DownloadStringAsync(new Uri(item.url, UriKind.Absolute));
}
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
urlist[?].result = e.Result;
}
我觉得完全卡住了。谢谢你的建议。
我遇到的问题是:我怎么知道哪个e.Result对应哪个url ?
有各种不同的选项:
UserState
您可以将第二个参数传递给DownloadStringAsync
,然后通过DownloadStringCompletedEventArgs.UserState
可用。例如:
// In your loop....
var wc = new WebClient();
wc.DownloadStringAsync(new Uri(item.url, UriKind.Absolute), item);
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
var item = (ressource) e.UserState;
item.result = e.Result;
}
多个WebClients 您可以为循环的每次迭代创建一个新的WebClient
,并为其附加不同的事件处理程序。lambda表达式在这里很有用:
// Note: this is broken in C# 3 and 4 due to the capture semantics of foreach.
// It should be fine in C# 5 though.
foreach(var item in urlist)
{
var wc = new WebClient();
wc.DownloadStringCompleted += (sender, args) => item.result = args.Result;
wc.DownloadStringAsync(new Uri(item.url, UriKind.Absolute));
}
DownloadStringTaskAsync
可以用DownloadStringTaskAsync
代替,这样每次调用都会返回一个Task<string>
。你可以保存这些元素的集合——每个元素对应一个urlist
——这样就可以知道哪个是哪个了。
或者,您可以同步获取所有结果,但我怀疑您不希望这样做。
不幸的是,WebClient
不支持多个并发连接,所以使用上面的所有选项,无论如何您应该在每次迭代中创建一个新的WebClient
。
另一个选择,也是我更喜欢的一个,是使用微软的响应式框架(Reactive Framework, Rx)。它为你处理所有的后台线程,类似于TPL,但通常更容易。
我是这样做的:
var query =
from x in urlist.ToObservable()
from result in Observable.Using(
() => new WebClient(),
wc => Observable.Start(() => wc.DownloadString(x.url)))
select new
{
x.url,
result
};
现在将结果返回到原始urlist
.
var lookup = urlist.ToDictionary(x => x.url);
query.Subscribe(x =>
{
lookup[x.url].result = x.result;
});
就这么简单。