后台工作程序中的多个异步webclient调用(Silverlight 4)

时间:2011-09-16 16:18:40

标签: c# silverlight asynchronous

要求

  • 从用户计算机加载文件的Silverlight客户端。
  • 对于文件中的每一行,它需要向URL发出GET,并根据返回的JSON验证消息批准或拒绝该行。
  • 当所有行都完成后,向用户显示已传递的行数和失败的行数的摘要。

我更喜欢在BackgroundWorker中“同步”执行此操作,但这会打破SL异步思维。

我的代码目前将结果从OpenFileDialog传递给BackgroundWorker,后者将文件读入强类型对象列表(客户端验证)。我创建一个WebClient并多次调用DownloadStringAsync,因为我循环遍历这些行。通常,后台工作程序在WebClient完成之前很久就完成并运行已完成的事件方法。 UI线程可以根据需要以异步方式运行,但我需要等待完成后台工作线程,直到它实际完成数据获取,或者有一些额外的事件处理程序在所有(数百)行已经过验证时有效。

想要处理X总事件的最后一次完成事件时,最佳做法是什么?在这里使用自动重置事件有什么用呢?

2 个答案:

答案 0 :(得分:1)

你不需要去那个后台线程,也不需要在这里使用AutoResetEvent。读取文件后,计算行数(=您要发送的请求数)并将其存储在实例变量中;然后触发所有WebRequest.DownloadAsync(或其他WebClient异步调用以下载数据)。在异步方法的每个回调中,您Interlock.Decrement实例变量,当它达到0时,您知道您拥有所有结果,并且您可以将摘要显示给客户端。

答案 1 :(得分:1)

您可以选择随机响应序列(但并行执行)  或顺序响应,但顺序模式。 有不同的缺点和优点。

using System;
using System.Net;
using System.Reactive.Linq;//Rx libriary
using System.Threading;
using System.Windows;
using System.Windows.Controls;

public partial class MainPage : UserControl
{
    private int count = 0;
    private int error = 0;

    public MainPage()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        ThreadPool.QueueUserWorkItem(StartParallel);
        //ThreadPool.QueueUserWorkItem(StartSequential);
    }

    private void Update(Exception exception)
    {
        if (exception == null)
            Interlocked.Increment(ref count);
        else
            Interlocked.Increment(ref error);
        if ((count%100) == 0)
        {
            int count1 = count;
            Dispatcher.BeginInvoke(() => { textBox.Text = count1.ToString(); });
        }
    }

    private void StartSequential(object o)
    {
        //single instance of  WebClient
        WebClient wc = new WebClient();
        var observer = Observable.FromEventPattern<DownloadStringCompletedEventArgs>(wc, "DownloadStringCompleted")
            .Select(newResult => new {newResult.EventArgs.Error, newResult.EventArgs.Result});

        wc.DownloadStringAsync(new Uri("http://localhost:7123/SilverlightApplication2TestPage.aspx"));
        int i = 0;
        foreach (var nextValue in observer.Next())
        {
            if (i == 10000) break;
            wc.DownloadStringAsync(new Uri("http://localhost:7123/SilverlightApplication2TestPage.aspx"));
            Update(nextValue.Error);
        }
    }

    private void StartParallel(object o)
    {
        for (int i = 0; i < 10000; i++)
        {
            //multiple instance of WebClient
            WebClient t = new WebClient();
            t.DownloadStringCompleted +=
                (x, nextValue) => Update(nextValue.Error);//order of result sequence is not guaranteed
            t.DownloadStringAsync(new Uri("http://localhost:7123/SilverlightApplication2TestPage.aspx"));
        }
    }
}