/// <summary> /// Handles an interaction and asynchronously returns the result. /// </summary> /// <remarks> /// <para> /// This method passes the interaction in turn to its registered handlers in reverse order of registration /// until one of them handles the interaction. If the interaction remains unhandled after all /// its registered handlers have executed, an <see cref="UnhandledInteractionException{TInput, TOutput}"/> is thrown. /// </para> /// </remarks> /// <param name="input"> /// The input for the interaction. /// </param> /// <returns> /// An observable that ticks when the interaction completes. /// </returns> /// <exception cref="UnhandledInteractionException{TInput, TOutput}">Thrown when no handler handles the interaction.</exception> public virtual IObservable <TOutput> Handle(TInput input) { var context = new InteractionContext <TInput, TOutput>(input); return(GetHandlers() .Reverse() .ToObservable() .ObserveOn(_handlerScheduler) .Select(handler => Observable.Defer(() => handler(context))) .Concat() .TakeWhile(_ => !context.IsHandled) .IgnoreElements() .Select(_ => default(TOutput) !) .Concat( Observable.Defer( () => context.IsHandled ? Observable.Return(context.GetOutput()) : Observable.Throw <TOutput>(new UnhandledInteractionException <TInput, TOutput>(this, input))))); }