RX - 在包含方法

时间:2018-02-02 11:37:02

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

我需要将RX流(IObservable)中的错误转换为包含流的订阅的方法中的异常

(由于此问题https://github.com/aspnet/SignalR/pull/1331,Whereby错误未被序列化到客户端。)一旦此问题得到解决,我将恢复正确处理错误

e.g。

我有以下方法

public IObservable<StreamItem> LiveStream()
{
    _mySvc.Start();
    return _mySvc.ThingChanged();
}

所以我试图订阅流并重新抛出错误,但它仍然没有传输到客户端:

public IObservable<StreamItem> LiveStream()
{
    _mySvc.Start();
    _mySvc.ThingChanged().Subscribe(item => {}, OnError, () => {});
    return _mySvc.ThingChanged();
}

private void OnError(Exception exception)
{
    throw new Exception(exception.Message);
}

我需要的是投入LiveStream方法的等效性

e.g。此错误传播给客户

public IObservable<StreamItem> LiveStream()
{
    _mySvc.Start();
    throw new Exception("some error message");
    return _mySvc.ThingChanged();
}

任何想法如何实现这一目标?

2 个答案:

答案 0 :(得分:1)

我也发现了这一点,尤其是在“包含”反应性管道的情况下,即具有明确定义的开始和结束的管道。在这种情况下,仅允许基础异常冒泡到包含作用域就足够了。但是,正如您所发现的那样,该概念通常对于Rx而言是陌生的:管道中发生的事情仍留在管道中。

我在一个包含的场景中发现的唯一方法是使用Catch()将错误“滑出”流,然后递回空的IObservable以允许流自然地停止(否则,如果您awaitIObservable完成,则会挂起)。

在您的LiveStream()方法内 ,这将不起作用,因为该上下文/作用域应该在消耗流之前很久就消失了。因此,这必须在包含整个管道的上下文中发生。

Exception error = null;
var source = LiveStream()
  .Catch<WhatYoureStreaming, Exception>(ex => {error = ex; return Observable.Empty<WhatYoureStreaming>(); })
  ...

await source; // if this is how you're awaiting completion

// not a real exception type, use your own
if (error != null) throw new ContainingException("oops", error);

最后不要throw error,您将丢失原始堆栈跟踪。

答案 1 :(得分:0)

试试这段代码:

public IObservable<StreamItem> LiveStream()
{
    _mySvc.Start();
    return
        _mySvc
            .ThingChanged()
            .Materialize()
            .Do(x =>
            {
                if (x.Kind == NotificationKind.OnError)
                {
                    OnError(x.Exception);
                }
            })
            .Dematerialize();
}

我不确定这是最好的方法 - 抛出这样的异常可能会导致你在流中遇到错误的异常处理程序。您可能需要找到另一种解决方案。