Observable。使用除

时间:2016-02-09 16:09:45

标签: c# asp.net-web-api async-await system.reactive

我有一个ASP.NET WebApi请求方法,该方法依次在遗留资源上使用Observable.Using启动异步调用。此资源将生成一个新线程,在该线程上,它会引发事件,然后这些事件将转换为由资源周围的包装器公开的OnNext流中的IObservable项。

await使用IObservable.FirstOrDefaultAsync() async我的WebApi方法将async标记为await

如果我采用这种设置,我会得到臭名昭着的

  

异步模块或处理程序   在异步操作仍未完成时完成

所以,我的第一个问题就是这个问题。我假设我已经得到了这个,因为遗留资源会产生新的异步操作(没有SynchronizationContext.Current._state.VoidAsyncOutstandingOperationCount / Dispose),但ASP.NET究竟是如何知道的呢?注册了什么?我发现ASP.NET正在查看Observable .Using( () => { Console.WriteLine($"Created on thread: {Thread.CurrentThread.ManagedThreadId}"); return Disposable.Create(() => { Console.WriteLine($"Disposed on thread: {Thread.CurrentThread.ManagedThreadId}"); }); }, _ => Observable.Return(1, NewThreadScheduler.Default)) .Do(_ => Console.WriteLine($"OnNext on thread: {Thread.CurrentThread.ManagedThreadId}")) .Wait(); 以便引发此异常,但是哪个调用会增加此属性?线程排队到ThreadPool?我相当确定这是由遗留资源制作的。

现在为什么在我处理资源时这些操作仍然存在?好吧,似乎Created on thread: 10 OnNext on thread: 11 Disposed on thread: 11 在传播事件的线程上运行,概念类似于下面的代码片段。

using

结果类似于:

Dispose

这是设计的吗?使用Dispose处理资源时,显然资源处于创建它的同一个线程上,因为代码是同步的。当Observable.Using在一个单独的线程上运行时,调用代码将继续运行,控制器将在await完全完成之前返回(大多数情况下,至少)。

如何以理智的方式缓解这个问题?一种似乎有用的方法是,使用这个返回给控制器的构造,而不是使用FirstOrDefaultAsync()var resource = // Creating resource manually. return resource.StartAsyncOperation() // <- observable producing events .ObserveOn(SynchronizationContext.Current) .Do(_ => resource.Dispose()); 使用Dispose

Observable.Using

这对我来说就像是一个黑客。

思考和建议?

编辑1

我想我在这里遇到的一个问题是,当我使用{{1> 序列终止/完成后,资源的Dispose方法被称为 }}。应该是这样的吗?在这种情况下,真的没有办法等待使用该构造的IObservable<Unit> Disposed()。我必须使用额外的render方法或类似的方法修改api ...

1 个答案:

答案 0 :(得分:1)

Dispose将在调用它的线程上调用(好吧)。更有帮助的是,在另一个调用OnComplete回调的线程上消耗/观察Rx序列时。如果您将Rx与标准运算符一起使用,那么当序列终止时(使用OnErrorOnComplete),您将获得自动处理行为。这种自动处理只会在OnComplete / OnError之后发生,并且只会在同一个线程上运行。

如果您希望将处置绑定到调度程序,那么我建议您查看System.Reactive.Disposables.ScheduledDisposable类型。但是,似乎在这里使用SynchronizationContext更自然,因此在这种情况下System.Reactive.Disposables.ContextDisposable可能更合适。