namespace Caliburn.Micro.Core { using System; /// /// A result decorator which rescues errors from the decorated result by executing a rescue coroutine. /// /// The type of the exception we want to perform the rescue on public class RescueResultDecorator : ResultDecoratorBase where TException : Exception { static readonly ILog Log = LogManager.GetLog(typeof(RescueResultDecorator<>)); readonly bool cancelResult; readonly Func coroutine; /// /// Initializes a new instance of the class. /// /// The result to decorate. /// The rescue coroutine. /// Set to true to cancel the result after executing rescue. public RescueResultDecorator(IResult result, Func coroutine, bool cancelResult = true) : base(result) { if (coroutine == null) throw new ArgumentNullException("coroutine"); this.coroutine = coroutine; this.cancelResult = cancelResult; } /// /// Called when the execution of the decorated result has completed. /// /// The context. /// The decorated result. /// The instance containing the event data. protected override void OnInnerResultCompleted(CoroutineExecutionContext context, IResult innerResult, ResultCompletionEventArgs args) { var error = args.Error as TException; if (error == null) { OnCompleted(args); } else { Log.Error(error); Log.Info(string.Format("Executing coroutine because {0} threw an exception.", innerResult.GetType().Name)); Rescue(context, error); } } void Rescue(CoroutineExecutionContext context, TException exception) { IResult rescueResult; try { rescueResult = coroutine(exception); } catch (Exception ex) { OnCompleted(new ResultCompletionEventArgs {Error = ex}); return; } try { rescueResult.Completed += RescueCompleted; IoC.BuildUp(rescueResult); rescueResult.Execute(context); } catch (Exception ex) { RescueCompleted(rescueResult, new ResultCompletionEventArgs {Error = ex}); } } void RescueCompleted(object sender, ResultCompletionEventArgs args) { ((IResult)sender).Completed -= RescueCompleted; OnCompleted(new ResultCompletionEventArgs { Error = args.Error, WasCancelled = (args.Error == null && (args.WasCancelled || cancelResult)) }); } } }