.Net Reactive Observable проблема: при использовании метода FromEvent () возникает исключение при попытке удалить подписку - PullRequest
1 голос
/ 31 мая 2019

Я использую метод Reactive .Net Observable FromEvent ():

 var someObservable = Observable.FromEvent<T>(dc => dataView.DataChanged += dc, dc =>  dataView.DataChanged -= dc)
 .Publish().Refcount();


 var subscription = someObservable.Subscribe(someHandler);

Подписка прошла успешно.Если я вызываю метод subscription.Dispose () в том же методе (в том же потоке с тем же контекстом синхронизации), он удаляется успешно.

Но на самом деле мне нужно избавиться от него позже.Мы используем концентраторы SignalR.Если я сохраню подписку, чтобы потом ее утилизировать, а затем попытаюсь вызвать

subscription.Dispose();

в другом потоке, я получу исключение: InvalidOperationException: "An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true".

Согласно документации, FromEvent () захватываетSynchronizationContext, чтобы вызвать addHandler и позже удалить его.На самом деле для нас выполнение обработчиков добавления и удаления в исходном контексте не важно, но я не нашел возможности предотвратить захват контекста syncronization методом FromEvent ().

Но если я сделаю хак и сделаю что-то вроде

await(Task.Run(() =>

        {
            SynchronizationContext.SetSynchronizationContext(context);

            subscription.Dispose();

        }));

где контекст - это тот контекст синхронизации, где вызывается FromEvent (), тогда он работает нормально, исключение не происходит.

Не могли бы вы уточнить, что на самом деле происходит, почему работает в предыдущем контекстеработает нормально но без этого не получается?

Я пытался вызвать метод SubscribeOn () и установить SynchronizationContext.Current (на самом деле это должно происходить из события).Попытался создать собственный планировщик и передать его в SubscribeOn или FromEvent (addHandler, removeHandler, scheduler).Всегда одно и то же исключение.

Попытка установить в web.config

add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" 

Таким образом, удаление подписки работает только в том случае, если я звоню

subscription.Dispose();

с сохраненным контентом синхронизации,но это не ясно и выглядит как взлом.

В моем коде нет асинхронных пустых операций.Методы, где подписка создается и где она уничтожается, вызываются из методов, вызываемых внутри методов SignalR Hub:

public async Task<OperationResult> Start()

{

// some code here

   await service.Start(); // service.Start() handles subscription creation
}


public async Task<OperationResult> Delete()

{

    await service.Delete(); // service.Delete() handles subscription disposing

}
...