Rx Observable - Chaining

时间:2012-03-22 20:20:53

标签: .net webclient system.reactive

我有一个从网上下载csv文件的功能。我需要对其进行扩展,以便一个接一个地对2个网站进行2次调用。但是我不知道怎么做......

Heres的功能是:

// Define other methods and classes here
private void GetCSVData(string url1, string url2)
{
    WebClient webClient = null;
    try
    {
        webClient = new WebClient();

        var task = Observable.FromEventPattern
            <OpenReadCompletedEventHandler, OpenReadCompletedEventArgs>
        (
            ev => webClient.OpenReadCompleted += ev,
            ev => webClient.OpenReadCompleted -= ev
        );

        // needs to be redone
        task.Subscribe(t => ParseCSV1(t.EventArgs.Result));

        // call ParseCSV1()
        // then call ParseCSV2()

        // needs redone, 2 calls to 2 website
        webClient.OpenReadAsync(new Uri(url1));     
    }
    catch (WebException wex)
    {
        System.Diagnostics.Debug.WriteLine(wex.ToString());
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.ToString());
    }
}

private void ParseCSV1(Stream stream)
{
    // Parse steps...
}

private void ParseCSV2(Stream stream)
{
    // Parse steps...
}

2 个答案:

答案 0 :(得分:1)

你拥有的应该可以。如果您再次拨打OpenReadAsync,则会触发第二个事件(每个网址一个),您的订阅将同时处理这两个事件。

您应该只需执行以下操作:

// Call both, will generate two events.
webClient.OpenReadAsync(new Uri(url1));
webClient.OpenReadAsync(new Uri(url2));

但是,我怀疑你有一些终身问题,因为你已经超出WebClient的范围(它从来没有被妥善处理过)。

答案 1 :(得分:0)

我个人不会在这里使用Rx。实际上,这听起来更适合任务库;这就像我可能做的那样:

void Main()
{
    var webClient = new System.Net.WebClient();

    Task.Factory
        .StartNew(() => GetUrl("http://www.google.com"))
        .ContinueWith(tsk => ParseCsv(CheckAndHandleError(tsk)))
        .ContinueWith(tsk => 
            { 
                if(CheckAndHandleError(tsk)) 
                    return GetUrl("http://www.yahoo.com"); 
                else
                    return string.Empty;
            })
        .ContinueWith(tsk => ParseCsv(CheckAndHandleError(tsk)));

}

private T CheckAndHandleError<T>(Task<T> task)
{
    if(task.IsFaulted)
    {
        // you'll need to handle the tsk.Exception here
        throw new NotImplementedException();
    }
    else
    {
        return task.Result;
    }   
}

private string GetUrl(string address)
{
    using(var client = new WebClient())
    {
        var stream = client.OpenRead(address);
        using(var rdr = new StreamReader(stream))
        {
            return rdr.ReadToEnd();
        }
    }
}

private bool ParseCsv(string csvText)
{
    // whatever this is
    Console.WriteLine(csvText);
    return true;
}