public void BeginPublish(TMessageType message) { if (_customTarget != null) { _customTarget(message); return; } FirLibMessenger.GetByName(this.SourceMessengerName) .BeginPublish(message); }
/// <summary> /// Initializes a new instance of the <see cref="MessageSubscription"/> class. /// </summary> /// <param name="messenger">The messenger.</param> /// <param name="messageType">Type of the message.</param> /// <param name="targetHandler">The target handler.</param> internal MessageSubscription(FirLibMessenger messenger, Type messageType, Delegate targetHandler) { _messenger = messenger; _messageType = messageType; _targetHandler = targetHandler; }
/// <summary> /// Sends the given message to all subscribers (sync processing). /// </summary> /// <typeparam name="TMessageType">Type of the message.</typeparam> /// <param name="message">The message to send.</param> /// <param name="isInitialCall">Is this one the initial call to publish? (false if we are coming from async routing)</param> private void PublishInternal <TMessageType>( TMessageType message, bool isInitialCall) { FirLibMessageHelper.EnsureValidMessageTypeAndValue(message); try { // Check whether publish is possible if (_publishCheckBehavior == FirLibMessengerThreadingBehavior.EnsureMainSyncContextOnSyncCalls) { if (!this.CompareSynchronizationContexts()) { throw new FirLibException( "Unable to perform a synchronous publish call because current " + "SynchronizationContext is set wrong. This indicates that the call " + "comes from a wrong thread!"); } } // Check for correct message sources Type currentType = typeof(TMessageType); if (isInitialCall) { string[] possibleSources = s_messageSources.GetOrAdd(currentType, (_) => FirLibMessageHelper.GetPossibleSourceMessengersOfMessageType(currentType)); if (possibleSources.Length > 0) { string mainThreadName = _globalMessengerName; if (string.IsNullOrEmpty(mainThreadName) || (Array.IndexOf(possibleSources, mainThreadName) < 0)) { throw new InvalidOperationException( $"The message of type {currentType.FullName} can only be sent " + $"by the threads [{possibleSources.ToCommaSeparatedString()}]. This Messenger " + $"belongs to the thread {(!string.IsNullOrEmpty(mainThreadName) ? mainThreadName : "(empty)")}, " + "so no publish possible!"); } } } // Perform synchronous message handling List <MessageSubscription> subscriptionsToTrigger = new(20); lock (_messageSubscriptionsLock) { if (_messageSubscriptions.ContainsKey(currentType)) { // Need to copy the list to avoid problems, when the list is changed during the loop and cross thread accesses subscriptionsToTrigger = new List <MessageSubscription>(_messageSubscriptions[currentType]); } } // Trigger all found subscriptions List <Exception>?occurredExceptions = null; for (var loop = 0; loop < subscriptionsToTrigger.Count; loop++) { try { subscriptionsToTrigger[loop].Publish(message); } catch (Exception ex) { occurredExceptions ??= new List <Exception>(); occurredExceptions.Add(ex); } } // Perform further message routing if enabled if (isInitialCall) { // Get information about message routing string[] asyncTargets = s_messagesAsyncTargets.GetOrAdd(currentType, (_) => FirLibMessageHelper.GetAsyncRoutingTargetMessengersOfMessageType(currentType)); string mainThreadName = _globalMessengerName; for (var loop = 0; loop < asyncTargets.Length; loop++) { string actAsyncTargetName = asyncTargets[loop]; if (mainThreadName == actAsyncTargetName) { continue; } if (s_messengersByName.TryGetValue(actAsyncTargetName, out var actAsyncTargetHandler)) { var actSyncContext = actAsyncTargetHandler !._hostSyncContext; if (actSyncContext == null) { continue; } FirLibMessenger innerHandlerForAsyncCall = actAsyncTargetHandler !; actSyncContext.PostAlsoIfNull(() => { innerHandlerForAsyncCall.PublishInternal(message, false); }); } } } // Notify all exceptions occurred during publish progress if (isInitialCall) { if ((occurredExceptions != null) && (occurredExceptions.Count > 0)) { throw new MessagePublishException(typeof(TMessageType), occurredExceptions); } } } catch (Exception ex) { // Check whether we have to throw the exception globally var globalExceptionHandler = CustomPublishExceptionHandler; var doRaise = true; if (globalExceptionHandler != null) { try { doRaise = !globalExceptionHandler(this, ex); } catch { doRaise = true; } } // Raise the exception to inform caller about it if (doRaise) { throw; } } }