/// <summary>
 /// Creates a new instance of communication exception.
 /// </summary>
 /// <param name="messageCausingException"></param>
 /// <param name="exceptionCatcher"></param>
 /// <param name="origin"></param>
 /// <param name="innerExceptions"></param>
 public NuntiusCommunicationException(NuntiusMessage messageCausingException,
     IEventSource exceptionCatcher,
     CommunicationExceptionOrigin origin,
     ReadOnlyCollection<Exception> innerExceptions)
 {
     MessageCausingException = messageCausingException;
     ExceptionCatcher = exceptionCatcher;
     InnerExceptions = innerExceptions;
     ExceptionOrigin = origin;
 }
 /// <summary>
 /// Returns a clone of this object. All properties are copied but the binary body. In that case, 
 /// only the references only exchanged.
 /// </summary>
 /// <returns></returns>
 public NuntiusMessage Clone()
 {
     var clone = new NuntiusMessage();
     foreach (var pair in Properties)
     {
         clone[pair.Key] = pair.Value;
     }
     clone.Body = Body;
     return clone;
 }
 /// <summary>
 /// Safely invokes <see cref="Send"/> event and handles and properly distributes any exceptions thrown in the process.
 /// </summary>
 /// <param name="message">Message to pass to the <see cref="IEventSource.Send"/> event.</param>
 protected void SafelyInvokeSendEvent(NuntiusMessage message)
 {
     try
     {
         switch (MonitoringOption)
         {
             case EventSourceCallbackMonitoringOptions.NotCheckTaskException:
                 Send?.Invoke(message);
                 break;
             case EventSourceCallbackMonitoringOptions.CheckTaskException:
                 if (Send != null)
                 {
                     foreach (Func<NuntiusMessage, Task> d in Send?.GetInvocationList())
                     {
                         d(message).ContinueWith(t =>
                         {
                             var ex = new NuntiusCommunicationException(message, this, CommunicationExceptionOrigin.ProcessTask,
                                 t.Exception?.InnerExceptions);
                             NuntiusConfiguration.DistributeException(ex);
                             switch (NuntiusConfiguration.CommunicationExceptionStrategy)
                             {
                                 case CommunicationExceptionStrategy.StopFlow:
                                     SafelyInvokeEndEvent();
                                     break;
                                 case CommunicationExceptionStrategy.ContinueFlow:
                                     break;
                                 default:
                                     throw new NotImplementedException($"Strategy for {NuntiusConfiguration.CommunicationExceptionStrategy} was not implemented.");
                             }
                         }, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
                     }
                 }
                 break;
             default:
                 throw new NotImplementedException($"Strategy for {MonitoringOption} was not implemented.");
         }
     }
     catch (Exception e)
     {
         var ex = new NuntiusCommunicationException(message, this, CommunicationExceptionOrigin.ProcessHandler,
             new ReadOnlyCollection<Exception>(new List<Exception>() { e }));
         NuntiusConfiguration.DistributeException(ex);
         switch (NuntiusConfiguration.CommunicationExceptionStrategy)
         {
             case CommunicationExceptionStrategy.StopFlow:
                 SafelyInvokeEndEvent();
                 break;
             case CommunicationExceptionStrategy.ContinueFlow:
                 break;
             default:
                 throw new NotImplementedException($"Strategy for {NuntiusConfiguration.CommunicationExceptionStrategy} was not implemented.");
         }
     }
 }