使用被动扩展以正确的顺序处理多个响应

时间:2015-10-20 14:35:51

标签: c# .net system.reactive reactive-programming

情况

我有一个系统,其中一个请求产生两个响应。请求和响应具有相应的可观察量:

IObservable<RequestSent> _requests;
IObservable<MainResponseReceived> _mainResponses;
IObservable<SecondResponseReceived> _secondaryResponses;

保证RequestSent事件早于MainResponseReceivedSecondaryResponseReceived,但响应按随机顺序排列。

我拥有什么

最初我想要处理两个响应的处理程序,所以我压缩了observables:

_requests
    .SelectMany(async request =>
    {
        var main = _mainResponses.FirstAsync(m => m.Id == request.Id);
        var secondary = _secondaryResponses.FirstAsync(s => s.Id == request.Id);

        var zippedResponse = main.Zip(secondary, (m, s) => new MainAndSecondaryResponseReceived {
            Request = request,
            Main = m, 
            Secondary = s
        });
        return await zippedResponse.FirstAsync(); ;
    })
    .Subscribe(OnMainAndSecondaryResponseReceived);

我需要什么

现在我还需要处理MainResponseReceived而不等待SecondaryResponseRecieved,并且必须保证,OnMainResponseRecieved在调用OnMainAndSecondaryResponseReceived之前完成

如何定义这两个订阅?

测试案例1:

    发生
  1. RequestSent
  2. MainResponseReceived发生 - &gt; OnMainResponseReceived被称为
  3. SecondaryResponseReceive d出现 - &gt; OnMainAndSecondaryResponseReceived被称为
  4. 测试案例2:

      发生
    1. RequestSent
    2. 发生
    3. SecondaryResponseReceived
    4. MainResponseReceived occurs - &gt; OnMainResponseReceived被称为 - &gt; OnMainAndSecondaryResponseReceived被称为

1 个答案:

答案 0 :(得分:1)

我认为你几乎走在正确的轨道上。我会停止使用所有Async的东西 - 这只是让事情变得复杂。

尝试此查询:

var query =
    _requests
        .SelectMany(request =>
            _mainResponses.Where(m => m.Id == request.Id).Take(1)
                .Do(m => OnMainResponseReceived(m))
                .Zip(
                    _secondaryResponses.Where(s => s.Id == request.Id).Take(1),
                    (m, s) => new MainAndSecondaryResponseReceived()
                    {
                        Request = request,
                        Main = m, 
                        Secondary = s
                    }));

var subscription =
    query.Subscribe(x => OnMainAndSecondaryResponseReceived(x));

.Do(...)是代码中重要的缺失部分。它确保在OnMainResponseReceived之前调用OnMainAndSecondaryResponseReceived,无论主要或次要响应是否首先出现。

我测试了这个:

Subject<RequestSent> _requestsSubject = new Subject<RequestSent>();
Subject<MainResponseReceived> _mainResponsesSubject = new Subject<MainResponseReceived>();
Subject<SecondResponseReceived> _secondaryResponsesSubject = new Subject<SecondResponseReceived>();

IObservable<RequestSent> _requests = _requestsSubject.AsObservable();
IObservable<MainResponseReceived> _mainResponses = _mainResponsesSubject.AsObservable();
IObservable<SecondResponseReceived> _secondaryResponses = _secondaryResponsesSubject.AsObservable();

_requestsSubject.OnNext(new RequestSent() { Id = 42 });
_mainResponsesSubject.OnNext(new MainResponseReceived() { Id = 42 });
_secondaryResponsesSubject.OnNext(new SecondResponseReceived() { Id = 42 });

_requestsSubject.OnNext(new RequestSent() { Id = 99 });
_mainResponsesSubject.OnNext(new MainResponseReceived() { Id = 99 });
_secondaryResponsesSubject.OnNext(new SecondResponseReceived() { Id = 99 });