Task ToObservable Обработка Ошибок


У меня есть следующий метод, который отвечает за вызов моего класса обслуживания и передачу результатов другому методу для сохранения их в моей БД:

public IObservable<bool> SyncSessions()
{
    var subject = new ReplaySubject<bool>();

    try
    {
        var query = new ByFilterQuery { SearchPeriodStartTime = DateTime.Now };
        var sessions = _sessionService.GetSessions(query).Result;
        var saved = SaveSessions(sessions);
        subject.OnNext(saved);
        subject.OnCompleted();
    }
    catch (Exception ex)
    {
        subject.OnError(ex);
    }

    return subject;
 }

_sessionService.GetSessions вызовет HttpRequestException, если сервер возвращает 500 или что-то подобное. У меня есть модульный тест, который высмеивает это поведение и хочет проверить, что мой метод изящно обрабатывает ошибку.

Есть ли лучшие способы распространения ошибки в моде Rx? Я пытался выполнение:

_sessionService.GetSessions(query).ToObservable().Select(SaveSessions);

Но это бросило мою ошибку вместо того, чтобы она была передана действию обработки ошибок в вызывающем методе. Я также планирую объединить этот метод с несколькими другими и обрабатывать ошибки в комбинированной усадьбе.

EDIT: вот как я подписывался на observable

Exception error = null;
_sessionManager
    .SyncSessions()
    .Subscribe(null, e => error = e);

Assert.That(error, Is.Not.Null.After(500));

Я передаю null в первый параметр, поскольку меня это не очень волнует в контексте этого теста

1 3

1 ответ:

Во-первых, для исходного кода, который вы опубликовали, я рекомендую использовать AsyncSubject вместо ReplaySubject. Считайте, что он оптимизирован для случая с одним результатом.

Теперь перейдем к вашему вопросу...

Всякий раз, когда наблюдаемый источник генерирует исключение, это исключение распространяется через обработчик OnError. Если при подписке на observable вы не предоставляете обработчик OnError, то будет выдано исключение.

Маленький код вы опубликовано:

_sessionService.GetSessions(query).ToObservable().Select(SaveSessions);

Этого недостаточно. Не публикуя также код, который показывает, как ВЫ подписываетесь на observable, я могу только догадываться, что вы не предоставили обработчик OnError.

Редактирование на основе тестового кода OP

Ваша фиктивная служба возвращает Task, которая создает исключение, или фиктивная служба просто создает исключение? Если вы не используете async / await, функцию, которая должна возвращать Task, но создает исключение при создании этого Task вызовет исключение немедленно вместо возврата failed Task. ToObservable никогда даже не вызывается, потому что GetSessions бросает. Если вы измените свой макет службы, чтобы вернуть неудачный Task, то ваш тест, вероятно, будет работать правильно.

Если вы хотите перехватывать немедленные исключения, а также неудачные задачи, то вы можете использовать Defer, чтобы отложить выполнение вашего метода до тех пор, пока наблюдатель не подпишется. Он также будет собирать сразу бросается исключениями в дополнение к искусству задачи:

return Observable
    .Defer(() => _sessionService.GetSessions(query))
    .Select(SaveSessions);