使用Rx异步读取webrequest

时间:2013-12-19 22:55:16

标签: httpwebrequest system.reactive

我正在尝试使用Rx对Web端点进行完全异步读取。我以一种丑陋的方式使用这样的东西:

        var reqUri = new Uri(string.Format("https://cds.cern.ch/record/{0}/export/xm?ln=en", docID));
        var wr = WebRequest.CreateHttp(reqUri);

        var s = Observable
                .FromAsyncPattern<WebResponse>(
                    wr.BeginGetResponse,
                    wr.EndGetResponse)
                .Invoke()
                .Catch(Observable.Return<WebResponse>(null))
                .Select(ExtractString)
                .Select(ParseToMD);

ExtractString是一种阻止方法,可以打开流并将其读回。不过,我想把它做为异步,但为了做到这一点,我遇到了一些麻烦。我认为以下内容应该有效:

        var s = Observable
                .FromAsyncPattern<WebResponse>(
                    wr.BeginGetResponse,
                    wr.EndGetResponse)
                .Invoke()
                .SelectMany(resp => Observable.Using(() => resp.GetResponseStream(), strm => Observable.Return(strm)))
                .SelectMany(resp => Observable.Using(() => new StreamReader(resp), strm => Observable.Return(strm)))
                .SelectMany(strm => Observable.FromAsync(tkn => strm.ReadToEndAsync()))
                .Select(ParseToMD);

而且,如果我在那里的某个点放置一个断点,有时候它会起作用。其他时候它只是挂起。所以,我有两个问题。首先,这是做这样的事情的正确方法吗?第二,调试这样的东西的最佳方法是什么?是否有一些我可以观看的跟踪显示事件通过系统?我刚刚在lambda函数中设置了断点。

ParseMD函数只是将字符串转换为一类数据。

1 个答案:

答案 0 :(得分:0)

您可以使用Spy method I present in this question跟踪流生存期。

你离这儿不远 - 我认为问题可能是你对Observable.Using有点过分热心。 Observable.Return可以完成导致竞争条件,其中可以在流阅读器完成之前处理响应流。我认为这可能会更可靠:

var reqUri = new Uri(
    string.Format("https://cds.cern.ch/record/{0}/export/xm?ln=en", docId));

var s = Observable.FromAsyncPattern<WebResponse>(
    wr.BeginGetResponse,
    wr.EndGetResponse)
    .Invoke()
    .Select(response => response.GetResponseStream())
    .SelectMany(stream =>
        Observable.Using(    () => new StreamReader(stream),
                         reader => Observable.StartAsync(reader.ReadToEndAsync)))
    .Select(ParseToMD);