区分多个webclient结果

时间:2014-03-14 20:24:06

标签: c# .net webclient

有一个清单。

我想通过webclient.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; 
 }

我觉得完全卡住了。 谢谢你的想法。

2 个答案:

答案 0 :(得分:3)

  

我遇到的问题是:我怎么知道哪个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;
}

多个WebClient

您可以为循环的每次迭代创建一个新的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并不支持多个并发连接,所以使用 all 上面的选项,无论如何都应该为每次迭代创建一个新的WebClient

答案 1 :(得分:2)

另一种替代方案,也就是我喜欢的方法,是使用Microsoft的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;
});

这很简单。