예제 #1
0
        /// <summary>
        /// Receives a <see cref="BrokeredMessage"/> from the event bus.
        /// </summary>
        protected virtual void ReceiveEvent(BrokeredMessage message)
        {
            DateTimeOffset startedAt     = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch = Stopwatch.StartNew();
            string         responseCode  = "200";
            // Null means it was skipped
            bool?              wasSuccessfull            = true;
            string             telemetryName             = string.Format("Cqrs/Handle/Event/{0}", message.MessageId);
            ISingleSignOnToken authenticationToken       = null;
            Guid?              guidAuthenticationToken   = null;
            string             stringAuthenticationToken = null;
            int?intAuthenticationToken = null;

            IDictionary <string, string> telemetryProperties = ExtractTelemetryProperties(message, "Azure/Servicebus");

            TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles++, telemetryProperties);
            var brokeredMessageRenewCancellationTokenSource = new CancellationTokenSource();

            try
            {
                Logger.LogDebug(string.Format("An event message arrived with the id '{0}'.", message.MessageId));
                string messageBody = message.GetBody <string>();

                IEvent <TAuthenticationToken> @event = AzureBusHelper.ReceiveEvent(messageBody, ReceiveEvent,
                                                                                   string.Format("id '{0}'", message.MessageId),
                                                                                   ExtractSignature(message),
                                                                                   SigningTokenConfigurationKey,
                                                                                   () =>
                {
                    wasSuccessfull = null;
                    telemetryName  = string.Format("Cqrs/Handle/Event/Skipped/{0}", message.MessageId);
                    responseCode   = "204";
                    // Remove message from queue
                    try
                    {
                        message.Complete();
                    }
                    catch (MessageLockLostException exception)
                    {
                        throw new MessageLockLostException(string.Format("The lock supplied for the skipped event message '{0}' is invalid.", message.MessageId), exception);
                    }
                    Logger.LogDebug(string.Format("An event message arrived with the id '{0}' but processing was skipped due to event settings.", message.MessageId));
                    TelemetryHelper.TrackEvent("Cqrs/Handle/Event/Skipped", telemetryProperties);
                },
                                                                                   () =>
                {
                    AzureBusHelper.RefreshLock(brokeredMessageRenewCancellationTokenSource, message, "event");
                }
                                                                                   );

                if (wasSuccessfull != null)
                {
                    if (@event != null)
                    {
                        telemetryName       = string.Format("{0}/{1}/{2}", @event.GetType().FullName, @event.GetIdentity(), @event.Id);
                        authenticationToken = @event.AuthenticationToken as ISingleSignOnToken;
                        if (AuthenticationTokenIsGuid)
                        {
                            guidAuthenticationToken = @event.AuthenticationToken as Guid?;
                        }
                        if (AuthenticationTokenIsString)
                        {
                            stringAuthenticationToken = @event.AuthenticationToken as string;
                        }
                        if (AuthenticationTokenIsInt)
                        {
                            intAuthenticationToken = @event.AuthenticationToken as int?;
                        }

                        var telemeteredMessage = @event as ITelemeteredMessage;
                        if (telemeteredMessage != null)
                        {
                            telemetryName = telemeteredMessage.TelemetryName;
                        }

                        telemetryName = string.Format("Cqrs/Handle/Event/{0}", telemetryName);
                    }
                    // Remove message from queue
                    try
                    {
                        message.Complete();
                    }
                    catch (MessageLockLostException exception)
                    {
                        throw new MessageLockLostException(string.Format("The lock supplied for event '{0}' of type {1} is invalid.", @event.Id, @event.GetType().Name), exception);
                    }
                }
                Logger.LogDebug(string.Format("An event message arrived and was processed with the id '{0}'.", message.MessageId));

                IList <IEvent <TAuthenticationToken> > events;
                if (EventWaits.TryGetValue(@event.CorrelationId, out events))
                {
                    events.Add(@event);
                }
            }
            catch (MessageLockLostException exception)
            {
                IDictionary <string, string> subTelemetryProperties = new Dictionary <string, string>(telemetryProperties);
                subTelemetryProperties.Add("TimeTaken", mainStopWatch.Elapsed.ToString());
                TelemetryHelper.TrackException(exception, null, subTelemetryProperties);
                if (ThrowExceptionOnReceiverMessageLockLostExceptionDuringComplete)
                {
                    Logger.LogError(exception.Message, exception: exception);
                    // Indicates a problem, unlock message in queue
                    message.Abandon();
                    wasSuccessfull = false;
                }
                else
                {
                    Logger.LogWarning(exception.Message, exception: exception);
                    try
                    {
                        message.DeadLetter("LockLostButHandled", "The message was handled but the lock was lost.");
                    }
                    catch (Exception)
                    {
                        // Oh well, move on.
                        message.Abandon();
                    }
                }
                responseCode = "599";
            }
            catch (UnAuthorisedMessageReceivedException exception)
            {
                TelemetryHelper.TrackException(exception, null, telemetryProperties);
                // Indicates a problem, unlock message in queue
                Logger.LogError(string.Format("An event message arrived with the id '{0}' but was not authorised.", message.MessageId), exception: exception);
                message.DeadLetter("UnAuthorisedMessageReceivedException", exception.Message);
                wasSuccessfull = false;
                responseCode   = "401";
                telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                telemetryProperties.Add("ExceptionMessage", exception.Message);
            }
            catch (NoHandlersRegisteredException exception)
            {
                TelemetryHelper.TrackException(exception, null, telemetryProperties);
                // Indicates a problem, unlock message in queue
                Logger.LogError(string.Format("An event message arrived with the id '{0}' but no handlers were found to process it.", message.MessageId), exception: exception);
                message.DeadLetter("NoHandlersRegisteredException", exception.Message);
                wasSuccessfull = false;
                responseCode   = "501";
                telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                telemetryProperties.Add("ExceptionMessage", exception.Message);
            }
            catch (NoHandlerRegisteredException exception)
            {
                TelemetryHelper.TrackException(exception, null, telemetryProperties);
                // Indicates a problem, unlock message in queue
                Logger.LogError(string.Format("An event message arrived with the id '{0}' but no handler was found to process it.", message.MessageId), exception: exception);
                message.DeadLetter("NoHandlerRegisteredException", exception.Message);
                wasSuccessfull = false;
                responseCode   = "501";
                telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                telemetryProperties.Add("ExceptionMessage", exception.Message);
            }
            catch (Exception exception)
            {
                TelemetryHelper.TrackException(exception, null, telemetryProperties);
                // Indicates a problem, unlock message in queue
                Logger.LogError(string.Format("An event message arrived with the id '{0}' but failed to be process.", message.MessageId), exception: exception);
                message.Abandon();
                wasSuccessfull = false;
                responseCode   = "500";
                telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                telemetryProperties.Add("ExceptionMessage", exception.Message);
            }
            finally
            {
                // Cancel the lock of renewing the task
                brokeredMessageRenewCancellationTokenSource.Cancel();
                TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles--, telemetryProperties);

                mainStopWatch.Stop();
                if (guidAuthenticationToken != null)
                {
                    TelemetryHelper.TrackRequest
                    (
                        telemetryName,
                        guidAuthenticationToken,
                        startedAt,
                        mainStopWatch.Elapsed,
                        responseCode,
                        wasSuccessfull == null || wasSuccessfull.Value,
                        telemetryProperties
                    );
                }
                else if (intAuthenticationToken != null)
                {
                    TelemetryHelper.TrackRequest
                    (
                        telemetryName,
                        intAuthenticationToken,
                        startedAt,
                        mainStopWatch.Elapsed,
                        responseCode,
                        wasSuccessfull == null || wasSuccessfull.Value,
                        telemetryProperties
                    );
                }
                else if (stringAuthenticationToken != null)
                {
                    TelemetryHelper.TrackRequest
                    (
                        telemetryName,
                        stringAuthenticationToken,
                        startedAt,
                        mainStopWatch.Elapsed,
                        responseCode,
                        wasSuccessfull == null || wasSuccessfull.Value,
                        telemetryProperties
                    );
                }
                else
                {
                    TelemetryHelper.TrackRequest
                    (
                        telemetryName,
                        authenticationToken,
                        startedAt,
                        mainStopWatch.Elapsed,
                        responseCode,
                        wasSuccessfull == null || wasSuccessfull.Value,
                        telemetryProperties
                    );
                }

                TelemetryHelper.Flush();
            }
        }
예제 #2
0
        /// <summary>
        /// Sends the provided <paramref name="command"></paramref> and waits for an event of <typeparamref name="TEvent"/> or exits if the specified timeout is expired.
        /// </summary>
        /// <param name="command">The <typeparamref name="TCommand"/> to send.</param>
        /// <param name="condition">A delegate to be executed over and over until it returns the <typeparamref name="TEvent"/> that is desired, return null to keep trying.</param>
        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see cref="F:System.Threading.Timeout.Infinite"/> (-1) to wait indefinitely.</param>
        /// <param name="eventReceiver">If provided, is the <see cref="IEventReceiver{TAuthenticationToken}" /> that the event is expected to be returned on.</param>
        public virtual TEvent PublishAndWait <TCommand, TEvent>(TCommand command, Func <IEnumerable <IEvent <TAuthenticationToken> >, TEvent> condition, int millisecondsTimeout,
                                                                IEventReceiver <TAuthenticationToken> eventReceiver = null) where TCommand : ICommand <TAuthenticationToken>
        {
            DateTimeOffset startedAt      = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch  = Stopwatch.StartNew();
            string         responseCode   = "200";
            bool           wasSuccessfull = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/EventHub" }
            };
            string telemetryName      = string.Format("{0}/{1}", command.GetType().FullName, command.Id);
            var    telemeteredCommand = command as ITelemeteredMessage;

            if (telemeteredCommand != null)
            {
                telemetryName = telemeteredCommand.TelemetryName;
            }
            telemetryName = string.Format("Command/{0}", telemetryName);

            TEvent result;

            try
            {
                if (eventReceiver != null)
                {
                    throw new NotSupportedException("Specifying a different event receiver is not yet supported.");
                }
                if (!AzureBusHelper.PrepareAndValidateCommand(command, "Azure-EventHub"))
                {
                    return((TEvent)(object)null);
                }

                result = (TEvent)(object)null;
                EventWaits.Add(command.CorrelationId, new List <IEvent <TAuthenticationToken> >());

                try
                {
                    EventHubPublisher.Send(new EventData(Encoding.UTF8.GetBytes(MessageSerialiser.SerialiseCommand(command))));
                }
                catch (Exception exception)
                {
                    responseCode = "500";
                    Logger.LogError("An issue occurred while trying to publish a command.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Command", command }
                    });
                    throw;
                }
                Logger.LogInfo(string.Format("A command was sent of type {0}.", command.GetType().FullName));
                wasSuccessfull = true;
            }
            finally
            {
                mainStopWatch.Stop();
                TelemetryHelper.TrackDependency("Azure/EventHub/CommandBus", "Command", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
            }

            SpinWait.SpinUntil(() =>
            {
                IList <IEvent <TAuthenticationToken> > events = EventWaits[command.CorrelationId];

                result = condition(events);

                return(result != null);
            }, millisecondsTimeout, 1000);

            TelemetryHelper.TrackDependency("Azure/EventHub/CommandBus", "Command/AndWait", string.Format("Command/AndWait{0}", telemetryName.Substring(7)), null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
            return(result);
        }
예제 #3
0
        /// <summary>
        /// Publishes the provided <paramref name="events"/> on the event bus.
        /// </summary>
        public virtual void Publish <TEvent>(IEnumerable <TEvent> events)
            where TEvent : IEvent <TAuthenticationToken>
        {
            IList <TEvent> sourceEvents = events.ToList();

            DateTimeOffset startedAt      = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch  = Stopwatch.StartNew();
            string         responseCode   = "200";
            bool           wasSuccessfull = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/EventHub" }
            };
            string telemetryName  = "Events";
            string telemetryNames = string.Empty;

            foreach (TEvent @event in sourceEvents)
            {
                string subTelemetryName = string.Format("{0}/{1}", @event.GetType().FullName, @event.Id);
                var    telemeteredEvent = @event as ITelemeteredMessage;
                if (telemeteredEvent != null)
                {
                    subTelemetryName = telemeteredEvent.TelemetryName;
                }
                telemetryNames = string.Format("{0}{1},", telemetryNames, subTelemetryName);
            }
            if (telemetryNames.Length > 0)
            {
                telemetryNames = telemetryNames.Substring(0, telemetryNames.Length - 1);
            }
            telemetryProperties.Add("Events", telemetryNames);

            try
            {
                IList <string> sourceEventMessages = new List <string>();
                IList <Microsoft.ServiceBus.Messaging.EventData> brokeredMessages = new List <Microsoft.ServiceBus.Messaging.EventData>(sourceEvents.Count);
                foreach (TEvent @event in sourceEvents)
                {
                    if (!AzureBusHelper.PrepareAndValidateEvent(@event, "Azure-EventHub"))
                    {
                        continue;
                    }

                    var brokeredMessage = new Microsoft.ServiceBus.Messaging.EventData(Encoding.UTF8.GetBytes(MessageSerialiser.SerialiseEvent(@event)));
                    brokeredMessage.Properties.Add("Type", @event.GetType().FullName);

                    brokeredMessages.Add(brokeredMessage);
                    sourceEventMessages.Add(string.Format("A command was sent of type {0}.", @event.GetType().FullName));
                }

                try
                {
                    EventHubPublisher.SendBatch(brokeredMessages);
                    wasSuccessfull = true;
                }
                catch (QuotaExceededException exception)
                {
                    responseCode = "429";
                    Logger.LogError("The size of the event being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Events", sourceEvents }
                    });
                    throw;
                }
                catch (Exception exception)
                {
                    responseCode = "500";
                    Logger.LogError("An issue occurred while trying to publish a event.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Events", sourceEvents }
                    });
                    throw;
                }

                foreach (string message in sourceEventMessages)
                {
                    Logger.LogInfo(message);
                }

                wasSuccessfull = true;
            }
            finally
            {
                mainStopWatch.Stop();
                TelemetryHelper.TrackDependency("Azure/EventHub/EventBus", "Event", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
            }
        }
예제 #4
0
 private void InitializeTelemetry()
 {
     // Fetch the session synchronously on the UI thread; if this doesn't happen before we try using this on
     // the background thread then the VS process will deadlock.
     TelemetryHelper.Initialize();
 }
예제 #5
0
        protected virtual void ReceiveCommand(BrokeredMessage message)
        {
            DateTimeOffset startedAt     = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch = Stopwatch.StartNew();
            string         responseCode  = "200";
            // Null means it was skipped
            bool?              wasSuccessfull      = true;
            string             telemetryName       = string.Format("Cqrs/Handle/Command/{0}", message.MessageId);
            ISingleSignOnToken authenticationToken = null;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            object value;

            if (message.Properties.TryGetValue("Type", out value))
            {
                telemetryProperties.Add("MessageType", value.ToString());
            }
            TelemetryHelper.TrackMetric("Cqrs/Handle/Command", CurrentHandles++, telemetryProperties);
            var brokeredMessageRenewCancellationTokenSource = new CancellationTokenSource();

            try
            {
                Logger.LogDebug(string.Format("A command message arrived with the id '{0}'.", message.MessageId));
                string messageBody = message.GetBody <string>();


                ICommand <TAuthenticationToken> command = AzureBusHelper.ReceiveCommand(messageBody, ReceiveCommand,
                                                                                        string.Format("id '{0}'", message.MessageId),
                                                                                        () =>
                {
                    wasSuccessfull = null;
                    telemetryName  = string.Format("Cqrs/Handle/Command/Skipped/{0}", message.MessageId);
                    responseCode   = "204";
                    // Remove message from queue
                    try
                    {
                        message.Complete();
                    }
                    catch (MessageLockLostException exception)
                    {
                        throw new MessageLockLostException(string.Format("The lock supplied for the skipped command message '{0}' is invalid.", message.MessageId), exception);
                    }
                    Logger.LogDebug(string.Format("A command message arrived with the id '{0}' but processing was skipped due to event settings.", message.MessageId));
                    TelemetryHelper.TrackEvent("Cqrs/Handle/Command/Skipped", telemetryProperties);
                },
                                                                                        () =>
                {
                    AzureBusHelper.RefreshLock(brokeredMessageRenewCancellationTokenSource, message, "command");
                }
                                                                                        );

                if (wasSuccessfull != null)
                {
                    if (command != null)
                    {
                        telemetryName       = string.Format("{0}/{1}", command.GetType().FullName, command.Id);
                        authenticationToken = command.AuthenticationToken as ISingleSignOnToken;

                        var telemeteredMessage = command as ITelemeteredMessage;
                        if (telemeteredMessage != null)
                        {
                            telemetryName = telemeteredMessage.TelemetryName;
                        }

                        telemetryName = string.Format("Cqrs/Handle/Command/{0}", telemetryName);
                    }
                    // Remove message from queue
                    try
                    {
                        message.Complete();
                    }
                    catch (MessageLockLostException exception)
                    {
                        throw new MessageLockLostException(string.Format("The lock supplied for command '{0}' of type {1} is invalid.", command.Id, command.GetType().Name), exception);
                    }
                }
                Logger.LogDebug(string.Format("A command message arrived and was processed with the id '{0}'.", message.MessageId));
            }
            catch (MessageLockLostException exception)
            {
                IDictionary <string, string> subTelemetryProperties = new Dictionary <string, string>(telemetryProperties);
                subTelemetryProperties.Add("TimeTaken", mainStopWatch.Elapsed.ToString());
                TelemetryHelper.TrackException(exception, null, subTelemetryProperties);
                if (ThrowExceptionOnReceiverMessageLockLostExceptionDuringComplete)
                {
                    Logger.LogError(exception.Message, exception: exception);
                    // Indicates a problem, unlock message in queue
                    message.Abandon();
                    wasSuccessfull = false;
                }
                else
                {
                    Logger.LogWarning(exception.Message, exception: exception);
                    try
                    {
                        message.DeadLetter("LockLostButHandled", "The message was handled but the lock was lost.");
                    }
                    catch (Exception)
                    {
                        // Oh well, move on.
                        message.Abandon();
                    }
                }
                responseCode = "599";
            }
            catch (Exception exception)
            {
                TelemetryHelper.TrackException(exception, null, telemetryProperties);
                // Indicates a problem, unlock message in queue
                Logger.LogError(string.Format("A command message arrived with the id '{0}' but failed to be process.", message.MessageId), exception: exception);
                message.Abandon();
                wasSuccessfull = false;
                responseCode   = "500";
                telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                telemetryProperties.Add("ExceptionMessage", exception.Message);
            }
            finally
            {
                // Cancel the lock of renewing the task
                brokeredMessageRenewCancellationTokenSource.Cancel();
                TelemetryHelper.TrackMetric("Cqrs/Handle/Command", CurrentHandles--, telemetryProperties);

                mainStopWatch.Stop();
                TelemetryHelper.TrackRequest
                (
                    telemetryName,
                    authenticationToken,
                    startedAt,
                    mainStopWatch.Elapsed,
                    responseCode,
                    wasSuccessfull == null || wasSuccessfull.Value,
                    telemetryProperties
                );

                TelemetryHelper.Flush();
            }
        }
예제 #6
0
        /// <summary>
        /// Using a <see cref="Task"/>, clears all dead letters from the topic and subscription of the
        /// provided <paramref name="topicName"/> and <paramref name="topicSubscriptionName"/>.
        /// </summary>
        /// <param name="topicName">The name of the topic.</param>
        /// <param name="topicSubscriptionName">The name of the subscription.</param>
        /// <returns></returns>
        protected virtual CancellationTokenSource CleanUpDeadLetters(string topicName, string topicSubscriptionName)
        {
            var brokeredMessageRenewCancellationTokenSource  = new CancellationTokenSource();
            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            int lockIssues = 0;

#if NET452
            Action <BrokeredMessage, IMessage> leaveDeadlLetterInQueue = (deadLetterBrokeredMessage, deadLetterMessage) =>
#endif
#if NETSTANDARD2_0
            Action <IMessageReceiver, BrokeredMessage, IMessage> leaveDeadlLetterInQueue = (client, deadLetterBrokeredMessage, deadLetterMessage) =>
#endif
            {
                // Remove message from queue
                try
                {
#if NET452
                    deadLetterBrokeredMessage.Abandon();
#endif
#if NETSTANDARD2_0
                    client.AbandonAsync(deadLetterBrokeredMessage.SystemProperties.LockToken).Wait(1500);
#endif
                    lockIssues = 0;
                }
                catch (MessageLockLostException)
                {
                    lockIssues++;
                    Logger.LogWarning(string.Format("The lock supplied for abandon for the skipped dead-letter message '{0}' is invalid.", deadLetterBrokeredMessage.MessageId));
                }
                Logger.LogDebug(string.Format("A dead-letter message of type {0} arrived with the id '{1}' but left in the queue due to settings.", deadLetterMessage.GetType().FullName, deadLetterBrokeredMessage.MessageId));
            };
#if NET452
            Action <BrokeredMessage> removeDeadlLetterFromQueue = (deadLetterBrokeredMessage) =>
#endif
#if NETSTANDARD2_0
            Action <IMessageReceiver, BrokeredMessage> removeDeadlLetterFromQueue = (client, deadLetterBrokeredMessage) =>
#endif
            {
                // Remove message from queue
                try
                {
#if NET452
                    deadLetterBrokeredMessage.Complete();
#endif
#if NETSTANDARD2_0
                    client.CompleteAsync(deadLetterBrokeredMessage.SystemProperties.LockToken).Wait(1500);
#endif
                    lockIssues = 0;
                }
                catch (MessageLockLostException)
                {
                    lockIssues++;
                    Logger.LogWarning(string.Format("The lock supplied for complete for the skipped dead-letter message '{0}' is invalid.", deadLetterBrokeredMessage.MessageId));
                }
                Logger.LogDebug(string.Format("A dead-letter message arrived with the id '{0}' but was removed as processing was skipped due to settings.", deadLetterBrokeredMessage.MessageId));
            };

            Task.Factory.StartNewSafely(() =>
            {
                int loop = 0;
                while (!brokeredMessageRenewCancellationTokenSource.Token.IsCancellationRequested)
                {
                    lockIssues = 0;
                    IEnumerable <BrokeredMessage> brokeredMessages;

#if NET452
                    MessagingFactory factory = MessagingFactory.CreateFromConnectionString(ConnectionString);
                    string deadLetterPath    = SubscriptionClient.FormatDeadLetterPath(topicName, topicSubscriptionName);
                    MessageReceiver client   = factory.CreateMessageReceiver(deadLetterPath, ReceiveMode.PeekLock);
                    brokeredMessages         = client.ReceiveBatch(1000);
#endif
#if NETSTANDARD2_0
                    string deadLetterPath  = EntityNameHelper.FormatDeadLetterPath(EntityNameHelper.FormatSubscriptionPath(topicName, topicSubscriptionName));
                    MessageReceiver client = new MessageReceiver(ConnectionString, deadLetterPath, ReceiveMode.PeekLock);
                    Task <IList <BrokeredMessage> > receiveTask = client.ReceiveAsync(1000);
                    receiveTask.Wait(10000);
                    if (receiveTask.IsCompleted && receiveTask.Result != null)
                    {
                        brokeredMessages = receiveTask.Result;
                    }
                    else
                    {
                        brokeredMessages = Enumerable.Empty <BrokeredMessage>();
                    }
#endif

                    foreach (BrokeredMessage brokeredMessage in brokeredMessages)
                    {
                        if (lockIssues > 10)
                        {
                            break;
                        }
                        try
                        {
                            Logger.LogDebug(string.Format("A dead-letter message arrived with the id '{0}'.", brokeredMessage.MessageId));
                            string messageBody = brokeredMessage.GetBodyAsString();

                            // Closure protection
                            BrokeredMessage message = brokeredMessage;
                            try
                            {
                                AzureBusHelper.ReceiveEvent
                                (
                                    messageBody,
                                    @event =>
                                {
                                    bool isRequired = BusHelper.IsEventRequired(@event.GetType());
                                    if (!isRequired)
                                    {
#if NET452
                                        removeDeadlLetterFromQueue(message);
#endif
#if NETSTANDARD2_0
                                        removeDeadlLetterFromQueue(client, message);
#endif
                                    }
                                    else
                                    {
#if NET452
                                        leaveDeadlLetterInQueue(message, @event);
#endif
#if NETSTANDARD2_0
                                        leaveDeadlLetterInQueue(client, message, @event);
#endif
                                    }
                                    return(true);
                                },
                                    string.Format("id '{0}'", brokeredMessage.MessageId),
                                    ExtractSignature(message),
                                    SigningTokenConfigurationKey,
                                    () =>
                                {
#if NET452
                                    removeDeadlLetterFromQueue(message);
#endif
#if NETSTANDARD2_0
                                    removeDeadlLetterFromQueue(client, message);
#endif
                                },
                                    () => { }
                                );
                            }
                            catch
                            {
                                AzureBusHelper.ReceiveCommand
                                (
                                    messageBody,
                                    command =>
                                {
                                    bool isRequired = BusHelper.IsEventRequired(command.GetType());
                                    if (!isRequired)
                                    {
#if NET452
                                        removeDeadlLetterFromQueue(message);
#endif
#if NETSTANDARD2_0
                                        removeDeadlLetterFromQueue(client, message);
#endif
                                    }
                                    else
                                    {
#if NET452
                                        leaveDeadlLetterInQueue(message, command);
#endif
#if NETSTANDARD2_0
                                        leaveDeadlLetterInQueue(client, message, command);
#endif
                                    }
                                    return(true);
                                },
                                    string.Format("id '{0}'", brokeredMessage.MessageId),
                                    ExtractSignature(message),
                                    SigningTokenConfigurationKey,
                                    () =>
                                {
#if NET452
                                    removeDeadlLetterFromQueue(message);
#endif
#if NETSTANDARD2_0
                                    removeDeadlLetterFromQueue(client, message);
#endif
                                },
                                    () => { }
                                );
                            }
                        }
                        catch (Exception exception)
                        {
                            TelemetryHelper.TrackException(exception, null, telemetryProperties);
                            // Indicates a problem, unlock message in queue
                            Logger.LogError(string.Format("A dead-letter message arrived with the id '{0}' but failed to be process.", brokeredMessage.MessageId), exception: exception);
                            try
                            {
#if NET452
                                brokeredMessage.Abandon();
#endif
#if NETSTANDARD2_0
                                client.AbandonAsync(brokeredMessage.SystemProperties.LockToken).Wait(1500);
#endif
                            }
                            catch (MessageLockLostException)
                            {
                                lockIssues++;
                                Logger.LogWarning(string.Format("The lock supplied for abandon for the skipped dead-letter message '{0}' is invalid.", brokeredMessage.MessageId));
                            }
                        }
                    }
#if NET452
                    client.Close();
#endif
#if NETSTANDARD2_0
                    client.CloseAsync().Wait(1500);
#endif

                    if (loop++ % 5 == 0)
                    {
                        loop = 0;
                        Thread.Yield();
                    }
                    else
                    {
                        Thread.Sleep(500);
                    }
                }
                try
                {
                    brokeredMessageRenewCancellationTokenSource.Dispose();
                }
                catch (ObjectDisposedException) { }
            }, brokeredMessageRenewCancellationTokenSource.Token);

            return(brokeredMessageRenewCancellationTokenSource);
        }
예제 #7
0
 private static void CheckIsSonarCloud(string uri)
 {
     TelemetryHelper.IsSonarCloud(new Uri(uri)).Should().BeTrue();
 }
예제 #8
0
        public virtual void Publish <TEvent>(TEvent @event)
            where TEvent : IEvent <TAuthenticationToken>
        {
            DateTimeOffset startedAt          = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch      = Stopwatch.StartNew();
            string         responseCode       = null;
            bool           mainWasSuccessfull = false;
            bool           telemeterOverall   = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            string telemetryName    = string.Format("{0}/{1}", @event.GetType().FullName, @event.Id);
            var    telemeteredEvent = @event as ITelemeteredMessage;

            if (telemeteredEvent != null)
            {
                telemetryName = telemeteredEvent.TelemetryName;
            }
            telemetryName = string.Format("Event/{0}", telemetryName);

            try
            {
                if (!AzureBusHelper.PrepareAndValidateEvent(@event, "Azure-ServiceBus"))
                {
                    return;
                }

                var privateEventAttribute = Attribute.GetCustomAttribute(typeof(TEvent), typeof(PrivateEventAttribute)) as PrivateEventAttribute;
                var publicEventAttribute  = Attribute.GetCustomAttribute(typeof(TEvent), typeof(PrivateEventAttribute)) as PublicEventAttribute;

                // We only add telemetry for overall operations if two occured
                telemeterOverall = publicEventAttribute != null && privateEventAttribute != null;

                // Backwards compatibility and simplicity
                bool      wasSuccessfull;
                Stopwatch stopWatch = Stopwatch.StartNew();
                if (publicEventAttribute == null && privateEventAttribute == null)
                {
                    stopWatch.Restart();
                    responseCode   = "200";
                    wasSuccessfull = false;
                    try
                    {
                        var brokeredMessage = new BrokeredMessage(MessageSerialiser.SerialiseEvent(@event))
                        {
                            CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                        };
                        brokeredMessage.Properties.Add("Type", @event.GetType().FullName);
                        PublicServiceBusPublisher.Send(brokeredMessage);
                        wasSuccessfull = true;
                    }
                    catch (QuotaExceededException exception)
                    {
                        responseCode = "429";
                        Logger.LogError("The size of the event being sent was too large or the topic has reached it's limit.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    catch (Exception exception)
                    {
                        responseCode = "500";
                        Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    finally
                    {
                        TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, "Default Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                    }
                    Logger.LogDebug(string.Format("An event was published on the public bus with the id '{0}' was of type {1}.", @event.Id, @event.GetType().FullName));
                }
                if (publicEventAttribute != null)
                {
                    stopWatch.Restart();
                    responseCode   = "200";
                    wasSuccessfull = false;
                    try
                    {
                        var brokeredMessage = new BrokeredMessage(MessageSerialiser.SerialiseEvent(@event))
                        {
                            CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                        };
                        brokeredMessage.Properties.Add("Type", @event.GetType().FullName);
                        PublicServiceBusPublisher.Send(brokeredMessage);
                        wasSuccessfull = true;
                    }
                    catch (QuotaExceededException exception)
                    {
                        responseCode = "429";
                        Logger.LogError("The size of the event being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    catch (Exception exception)
                    {
                        responseCode = "500";
                        Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    finally
                    {
                        TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, "Public Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                    }
                    Logger.LogDebug(string.Format("An event was published on the public bus with the id '{0}' was of type {1}.", @event.Id, @event.GetType().FullName));
                }
                if (privateEventAttribute != null)
                {
                    stopWatch.Restart();
                    responseCode   = "200";
                    wasSuccessfull = false;
                    try
                    {
                        var brokeredMessage = new BrokeredMessage(MessageSerialiser.SerialiseEvent(@event))
                        {
                            CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                        };
                        brokeredMessage.Properties.Add("Type", @event.GetType().FullName);
                        PrivateServiceBusPublisher.Send(brokeredMessage);
                        wasSuccessfull = true;
                    }
                    catch (QuotaExceededException exception)
                    {
                        responseCode = "429";
                        Logger.LogError("The size of the event being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    catch (Exception exception)
                    {
                        responseCode = "500";
                        Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    finally
                    {
                        TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, "Private Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                    }

                    Logger.LogDebug(string.Format("An event was published on the private bus with the id '{0}' was of type {1}.", @event.Id, @event.GetType().FullName));
                }
                mainWasSuccessfull = true;
            }
            finally
            {
                mainStopWatch.Stop();
                if (telemeterOverall)
                {
                    TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, mainWasSuccessfull, telemetryProperties);
                }
            }
        }
        /// <summary>
        /// Receives a <see cref="EventData"/> from the event bus.
        /// </summary>
        protected virtual void ReceiveEvent(PartitionContext context, EventData eventData)
        {
            DateTimeOffset startedAt     = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch = Stopwatch.StartNew();
            string         responseCode  = "200";
            // Null means it was skipped
            bool?wasSuccessfull = true;

#if NET452
            string telemetryName = string.Format("Cqrs/Handle/Event/{0}", eventData.SequenceNumber);
#endif
#if NETSTANDARD2_0
            string telemetryName = string.Format("Cqrs/Handle/Event/{0}", eventData.SystemProperties.SequenceNumber);
#endif
            ISingleSignOnToken authenticationToken = null;
            Guid?  guidAuthenticationToken         = null;
            string stringAuthenticationToken       = null;
            int?   intAuthenticationToken          = null;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/EventHub" }
            };
            object value;
            if (eventData.Properties.TryGetValue("Type", out value))
            {
                telemetryProperties.Add("MessageType", value.ToString());
            }
            TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles++, telemetryProperties);
            // Do a manual 10 try attempt with back-off
            for (int i = 0; i < 10; i++)
            {
                try
                {
#if NET452
                    Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset));
#endif
#if NETSTANDARD2_0
                    Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset));
#endif
#if NET452
                    string messageBody = Encoding.UTF8.GetString(eventData.GetBytes());
#endif
#if NETSTANDARD2_0
                    string messageBody = Encoding.UTF8.GetString(eventData.Body.Array, eventData.Body.Offset, eventData.Body.Count);
#endif

                    IEvent <TAuthenticationToken> @event = AzureBusHelper.ReceiveEvent(null, messageBody, ReceiveEvent,
#if NET452
                                                                                       string.Format("partition key '{0}', sequence number '{1}' and offset '{2}'", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset),
#endif
#if NETSTANDARD2_0
                                                                                       string.Format("partition key '{0}', sequence number '{1}' and offset '{2}'", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset),
#endif
                                                                                       ExtractSignature(eventData),
                                                                                       SigningTokenConfigurationKey,
                                                                                       () =>
                    {
                        wasSuccessfull = null;
#if NET452
                        telemetryName = string.Format("Cqrs/Handle/Event/Skipped/{0}", eventData.SequenceNumber);
#endif
#if NETSTANDARD2_0
                        telemetryName = string.Format("Cqrs/Handle/Event/Skipped/{0}", eventData.SystemProperties.SequenceNumber);
#endif
                        responseCode = "204";
                        // Remove message from queue
                        context.CheckpointAsync(eventData);
#if NET452
                        Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but processing was skipped due to event settings.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset));
#endif
#if NETSTANDARD2_0
                        Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but processing was skipped due to event settings.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset));
#endif
                        TelemetryHelper.TrackEvent("Cqrs/Handle/Event/Skipped", telemetryProperties);
                    }
                                                                                       );

                    if (wasSuccessfull != null)
                    {
                        if (@event != null)
                        {
                            telemetryName       = string.Format("{0}/{1}/{2}", @event.GetType().FullName, @event.GetIdentity(), @event.Id);
                            authenticationToken = @event.AuthenticationToken as ISingleSignOnToken;
                            if (AuthenticationTokenIsGuid)
                            {
                                guidAuthenticationToken = @event.AuthenticationToken as Guid?;
                            }
                            if (AuthenticationTokenIsString)
                            {
                                stringAuthenticationToken = @event.AuthenticationToken as string;
                            }
                            if (AuthenticationTokenIsInt)
                            {
                                intAuthenticationToken = @event.AuthenticationToken as int?;
                            }

                            var telemeteredMessage = @event as ITelemeteredMessage;
                            if (telemeteredMessage != null)
                            {
                                telemetryName = telemeteredMessage.TelemetryName;
                            }

                            telemetryName = string.Format("Cqrs/Handle/Event/{0}", telemetryName);
                        }
                        // Remove message from queue
                        context.CheckpointAsync(eventData);
                    }
#if NET452
                    Logger.LogDebug(string.Format("An event message arrived and was processed with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset));
#endif
#if NETSTANDARD2_0
                    Logger.LogDebug(string.Format("An event message arrived and was processed with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset));
#endif

                    IList <IEvent <TAuthenticationToken> > events;
                    if (EventWaits.TryGetValue(@event.CorrelationId, out events))
                    {
                        events.Add(@event);
                    }

                    wasSuccessfull = true;
                    responseCode   = "200";
                    return;
                }
                catch (UnAuthorisedMessageReceivedException exception)
                {
                    TelemetryHelper.TrackException(exception, null, telemetryProperties);
                    // Indicates a problem, unlock message in queue
#if NET452
                    Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but was not authorised.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception);
#endif
#if NETSTANDARD2_0
                    Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but was not authorised.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset), exception: exception);
#endif
                    wasSuccessfull = false;
                    responseCode   = "401";
                    telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                    telemetryProperties.Add("ExceptionMessage", exception.Message);
                }
                catch (NoHandlersRegisteredException exception)
                {
                    TelemetryHelper.TrackException(exception, null, telemetryProperties);
                    // Indicates a problem, unlock message in queue
#if NET452
                    Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but no handlers were found to process it.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception);
#endif
#if NETSTANDARD2_0
                    Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but no handlers were found to process it.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset), exception: exception);
#endif
                    wasSuccessfull = false;
                    responseCode   = "501";
                    telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                    telemetryProperties.Add("ExceptionMessage", exception.Message);
                }
                catch (NoHandlerRegisteredException exception)
                {
                    TelemetryHelper.TrackException(exception, null, telemetryProperties);
                    // Indicates a problem, unlock message in queue
#if NET452
                    Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}'s but no handler was found to process it.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception);
#endif
#if NETSTANDARD2_0
                    Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}'s but no handler was found to process it.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset), exception: exception);
#endif
                    wasSuccessfull = false;
                    responseCode   = "501";
                    telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                    telemetryProperties.Add("ExceptionMessage", exception.Message);
                }
                catch (Exception exception)
                {
                    // Indicates a problem, unlock message in queue
#if NET452
                    Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but failed to be process.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception);
#endif
#if NETSTANDARD2_0
                    Logger.LogError(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but failed to be process.", eventData.SystemProperties.PartitionKey, eventData.SystemProperties.SequenceNumber, eventData.SystemProperties.Offset), exception: exception);
#endif

                    switch (i)
                    {
                    case 0:
                    case 1:
                        // 10 seconds
                        Thread.Sleep(10 * 1000);
                        break;

                    case 2:
                    case 3:
                        // 30 seconds
                        Thread.Sleep(30 * 1000);
                        break;

                    case 4:
                    case 5:
                    case 6:
                        // 1 minute
                        Thread.Sleep(60 * 1000);
                        break;

                    case 7:
                    case 8:
                        // 3 minutes
                        Thread.Sleep(3 * 60 * 1000);
                        break;

                    case 9:
                        telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                        telemetryProperties.Add("ExceptionMessage", exception.Message);
                        break;
                    }
                    wasSuccessfull = false;
                    responseCode   = "500";
                }
                finally
                {
                    // Eventually just accept it
                    context.CheckpointAsync(eventData);

                    TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles--, telemetryProperties);

                    mainStopWatch.Stop();
                    if (guidAuthenticationToken != null)
                    {
                        TelemetryHelper.TrackRequest
                        (
                            telemetryName,
                            guidAuthenticationToken,
                            startedAt,
                            mainStopWatch.Elapsed,
                            responseCode,
                            wasSuccessfull == null || wasSuccessfull.Value,
                            telemetryProperties
                        );
                    }
                    else if (intAuthenticationToken != null)
                    {
                        TelemetryHelper.TrackRequest
                        (
                            telemetryName,
                            intAuthenticationToken,
                            startedAt,
                            mainStopWatch.Elapsed,
                            responseCode,
                            wasSuccessfull == null || wasSuccessfull.Value,
                            telemetryProperties
                        );
                    }
                    else if (stringAuthenticationToken != null)
                    {
                        TelemetryHelper.TrackRequest
                        (
                            telemetryName,
                            stringAuthenticationToken,
                            startedAt,
                            mainStopWatch.Elapsed,
                            responseCode,
                            wasSuccessfull == null || wasSuccessfull.Value,
                            telemetryProperties
                        );
                    }
                    else
                    {
                        TelemetryHelper.TrackRequest
                        (
                            telemetryName,
                            authenticationToken,
                            startedAt,
                            mainStopWatch.Elapsed,
                            responseCode,
                            wasSuccessfull == null || wasSuccessfull.Value,
                            telemetryProperties
                        );
                    }

                    TelemetryHelper.Flush();
                }
            }
        }
        /// <summary>
        /// Publishes the provided <paramref name="command"></paramref> and waits for an event of <typeparamref name="TEvent"/> or exits if the specified timeout is expired.
        /// </summary>
        /// <param name="command">The <typeparamref name="TCommand"/> to publish.</param>
        /// <param name="condition">A delegate to be executed over and over until it returns the <typeparamref name="TEvent"/> that is desired, return null to keep trying.</param>
        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see cref="F:System.Threading.Timeout.Infinite"/> (-1) to wait indefinitely.</param>
        /// <param name="eventReceiver">If provided, is the <see cref="IEventReceiver{TAuthenticationToken}" /> that the event is expected to be returned on.</param>
        public virtual TEvent PublishAndWait <TCommand, TEvent>(TCommand command, Func <IEnumerable <IEvent <TAuthenticationToken> >, TEvent> condition, int millisecondsTimeout,
                                                                IEventReceiver <TAuthenticationToken> eventReceiver = null) where TCommand : ICommand <TAuthenticationToken>
        {
            if (command == null)
            {
                Logger.LogDebug("No command to publish.");
                return((TEvent)(object)null);
            }
            Type           commandType    = command.GetType();
            DateTimeOffset startedAt      = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch  = Stopwatch.StartNew();
            string         responseCode   = "200";
            bool           wasSuccessfull = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            string telemetryName      = string.Format("{0}/{1}", commandType.FullName, command.Id);
            var    telemeteredCommand = command as ITelemeteredMessage;

            if (telemeteredCommand != null)
            {
                telemetryName = telemeteredCommand.TelemetryName;
            }
            telemetryName = string.Format("Command/{0}", telemetryName);

            TEvent result;

            try
            {
                if (eventReceiver != null)
                {
                    throw new NotSupportedException("Specifying a different event receiver is not yet supported.");
                }
                if (!AzureBusHelper.PrepareAndValidateCommand(command, "Azure-ServiceBus"))
                {
                    return((TEvent)(object)null);
                }

                result = (TEvent)(object)null;
                EventWaits.Add(command.CorrelationId, new List <IEvent <TAuthenticationToken> >());

                try
                {
                    var brokeredMessage = new BrokeredMessage(MessageSerialiser.SerialiseCommand(command))
                    {
                        CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                    };
                    brokeredMessage.Properties.Add("Type", commandType.FullName);
                    brokeredMessage.Properties.Add("Source", string.Format("{0}/{1}/{2}/{3}", LoggerSettings.ModuleName, LoggerSettings.Instance, LoggerSettings.Environment, LoggerSettings.EnvironmentInstance));
                    int count = 1;
                    do
                    {
                        try
                        {
                            PrivateServiceBusPublisher.Send(brokeredMessage);
                            break;
                        }
                        catch (TimeoutException)
                        {
                            if (count >= TimeoutOnSendRetryMaximumCount)
                            {
                                throw;
                            }
                        }
                        count++;
                    } while (true);
                }
                catch (QuotaExceededException exception)
                {
                    responseCode = "429";
                    Logger.LogError("The size of the command being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Command", command }
                    });
                    throw;
                }
                catch (Exception exception)
                {
                    responseCode = "500";
                    Logger.LogError("An issue occurred while trying to publish a command.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Command", command }
                    });
                    throw;
                }
                Logger.LogInfo(string.Format("A command was sent of type {0}.", commandType.FullName));
                wasSuccessfull = true;
            }
            finally
            {
                mainStopWatch.Stop();
                TelemetryHelper.TrackDependency("Azure/Servicebus/CommandBus", "Command", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
            }

            SpinWait.SpinUntil(() =>
            {
                IList <IEvent <TAuthenticationToken> > events = EventWaits[command.CorrelationId];

                result = condition(events);

                return(result != null);
            }, millisecondsTimeout, sleepInMilliseconds: 1000);

            TelemetryHelper.TrackDependency("Azure/Servicebus/CommandBus", "Command/AndWait", string.Format("Command/AndWait{0}", telemetryName.Substring(7)), null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
            return(result);
        }
        /// <summary>
        /// Publishes the provided <paramref name="command"/> on the command bus.
        /// </summary>
        public virtual void Publish <TCommand>(TCommand command)
            where TCommand : ICommand <TAuthenticationToken>
        {
            if (command == null)
            {
                Logger.LogDebug("No command to publish.");
                return;
            }
            Type           commandType        = command.GetType();
            DateTimeOffset startedAt          = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch      = Stopwatch.StartNew();
            string         responseCode       = "200";
            bool           mainWasSuccessfull = false;
            bool           telemeterOverall   = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            string telemetryName      = string.Format("{0}/{1}/{2}", commandType.FullName, command.GetIdentity(), command.Id);
            var    telemeteredCommand = command as ITelemeteredMessage;

            if (telemeteredCommand != null)
            {
                telemetryName = telemeteredCommand.TelemetryName;
            }
            else
            {
                telemetryName = string.Format("Command/{0}", telemetryName);
            }

            try
            {
                if (!AzureBusHelper.PrepareAndValidateCommand(command, "Azure-ServiceBus"))
                {
                    return;
                }

                bool?isPublicBusRequired  = BusHelper.IsPublicBusRequired(commandType);
                bool?isPrivateBusRequired = BusHelper.IsPrivateBusRequired(commandType);

                // We only add telemetry for overall operations if two occured
                telemeterOverall = isPublicBusRequired != null && isPublicBusRequired.Value && isPrivateBusRequired != null && isPrivateBusRequired.Value;

                // Backwards compatibility and simplicity
                bool      wasSuccessfull;
                Stopwatch stopWatch = Stopwatch.StartNew();
                if ((isPublicBusRequired == null || !isPublicBusRequired.Value) && (isPrivateBusRequired == null || !isPrivateBusRequired.Value))
                {
                    stopWatch.Restart();
                    responseCode   = "200";
                    wasSuccessfull = false;
                    try
                    {
                        var brokeredMessage = new BrokeredMessage(MessageSerialiser.SerialiseCommand(command))
                        {
                            CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                        };
                        brokeredMessage.Properties.Add("Type", commandType.FullName);
                        brokeredMessage.Properties.Add("Source", string.Format("{0}/{1}/{2}/{3}", LoggerSettings.ModuleName, LoggerSettings.Instance, LoggerSettings.Environment, LoggerSettings.EnvironmentInstance));
                        int count = 1;
                        do
                        {
                            try
                            {
                                PublicServiceBusPublisher.Send(brokeredMessage);
                                break;
                            }
                            catch (TimeoutException)
                            {
                                if (count >= TimeoutOnSendRetryMaximumCount)
                                {
                                    throw;
                                }
                            }
                            count++;
                        } while (true);
                        wasSuccessfull = true;
                    }
                    catch (QuotaExceededException exception)
                    {
                        responseCode = "429";
                        Logger.LogError("The size of the command being sent was too large or the topic has reached it's limit.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Command", command }
                        });
                        throw;
                    }
                    catch (Exception exception)
                    {
                        responseCode = "500";
                        Logger.LogError("An issue occurred while trying to publish a command.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Command", command }
                        });
                        throw;
                    }
                    finally
                    {
                        TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Command", telemetryName, "Default Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                    }
                    Logger.LogDebug(string.Format("An command was published on the public bus with the id '{0}' was of type {1}.", command.Id, commandType.FullName));
                }
                if ((isPublicBusRequired != null && isPublicBusRequired.Value))
                {
                    stopWatch.Restart();
                    responseCode   = "200";
                    wasSuccessfull = false;
                    try
                    {
                        var brokeredMessage = new BrokeredMessage(MessageSerialiser.SerialiseCommand(command))
                        {
                            CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                        };
                        brokeredMessage.Properties.Add("Type", commandType.FullName);
                        brokeredMessage.Properties.Add("Source", string.Format("{0}/{1}/{2}/{3}", LoggerSettings.ModuleName, LoggerSettings.Instance, LoggerSettings.Environment, LoggerSettings.EnvironmentInstance));
                        int count = 1;
                        do
                        {
                            try
                            {
                                PublicServiceBusPublisher.Send(brokeredMessage);
                                break;
                            }
                            catch (TimeoutException)
                            {
                                if (count >= TimeoutOnSendRetryMaximumCount)
                                {
                                    throw;
                                }
                            }
                            count++;
                        } while (true);
                        wasSuccessfull = true;
                    }
                    catch (QuotaExceededException exception)
                    {
                        responseCode = "429";
                        Logger.LogError("The size of the command being sent was too large or the topic has reached it's limit.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Command", command }
                        });
                        throw;
                    }
                    catch (Exception exception)
                    {
                        responseCode = "500";
                        Logger.LogError("An issue occurred while trying to publish a command.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Command", command }
                        });
                        throw;
                    }
                    finally
                    {
                        TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Command", telemetryName, "Public Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                    }
                    Logger.LogDebug(string.Format("An command was published on the public bus with the id '{0}' was of type {1}.", command.Id, commandType.FullName));
                }
                if (isPrivateBusRequired != null && isPrivateBusRequired.Value)
                {
                    stopWatch.Restart();
                    responseCode   = "200";
                    wasSuccessfull = false;
                    try
                    {
                        var brokeredMessage = new BrokeredMessage(MessageSerialiser.SerialiseCommand(command))
                        {
                            CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                        };
                        brokeredMessage.Properties.Add("Type", commandType.FullName);
                        brokeredMessage.Properties.Add("Source", string.Format("{0}/{1}/{2}/{3}", LoggerSettings.ModuleName, LoggerSettings.Instance, LoggerSettings.Environment, LoggerSettings.EnvironmentInstance));
                        int count = 1;
                        do
                        {
                            try
                            {
                                PrivateServiceBusPublisher.Send(brokeredMessage);
                                break;
                            }
                            catch (TimeoutException)
                            {
                                if (count >= TimeoutOnSendRetryMaximumCount)
                                {
                                    throw;
                                }
                            }
                            count++;
                        } while (true);
                        wasSuccessfull = true;
                    }
                    catch (QuotaExceededException exception)
                    {
                        responseCode = "429";
                        Logger.LogError("The size of the command being sent was too large or the topic has reached it's limit.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Command", command }
                        });
                        throw;
                    }
                    catch (Exception exception)
                    {
                        responseCode = "500";
                        Logger.LogError("An issue occurred while trying to publish an command.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Command", command }
                        });
                        throw;
                    }
                    finally
                    {
                        TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Command", telemetryName, "Private Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                    }

                    Logger.LogDebug(string.Format("An command was published on the private bus with the id '{0}' was of type {1}.", command.Id, commandType.FullName));
                }
                mainWasSuccessfull = true;
            }
            finally
            {
                mainStopWatch.Stop();
                if (telemeterOverall)
                {
                    TelemetryHelper.TrackDependency("Azure/Servicebus/CommandBus", "Command", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, mainWasSuccessfull, telemetryProperties);
                }
            }
        }
        /// <summary>
        /// Publishes the provided <paramref name="commands"/> on the command bus.
        /// </summary>
        public virtual void Publish <TCommand>(IEnumerable <TCommand> commands)
            where TCommand : ICommand <TAuthenticationToken>
        {
            if (commands == null)
            {
                Logger.LogDebug("No commands to publish.");
                return;
            }
            IList <TCommand> sourceCommands = commands.ToList();

            if (!sourceCommands.Any())
            {
                Logger.LogDebug("An empty collection of commands to publish.");
                return;
            }

            DateTimeOffset startedAt      = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch  = Stopwatch.StartNew();
            string         responseCode   = "200";
            bool           wasSuccessfull = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            string telemetryName  = "Commands";
            string telemetryNames = string.Empty;

            foreach (TCommand command in sourceCommands)
            {
                Type   commandType        = command.GetType();
                string subTelemetryName   = string.Format("{0}/{1}", commandType.FullName, command.Id);
                var    telemeteredCommand = command as ITelemeteredMessage;
                if (telemeteredCommand != null)
                {
                    subTelemetryName = telemeteredCommand.TelemetryName;
                }
                telemetryNames = string.Format("{0}{1},", telemetryNames, subTelemetryName);
            }
            if (telemetryNames.Length > 0)
            {
                telemetryNames = telemetryNames.Substring(0, telemetryNames.Length - 1);
            }
            telemetryProperties.Add("Commands", telemetryNames);

            try
            {
                IList <string>          sourceCommandMessages = new List <string>();
                IList <BrokeredMessage> brokeredMessages      = new List <BrokeredMessage>(sourceCommands.Count);
                foreach (TCommand command in sourceCommands)
                {
                    Type commandType = command.GetType();
                    if (!AzureBusHelper.PrepareAndValidateCommand(command, "Azure-ServiceBus"))
                    {
                        continue;
                    }

                    var brokeredMessage = new BrokeredMessage(MessageSerialiser.SerialiseCommand(command))
                    {
                        CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                    };
                    brokeredMessage.Properties.Add("Type", commandType.FullName);
                    brokeredMessage.Properties.Add("Source", string.Format("{0}/{1}/{2}/{3}", LoggerSettings.ModuleName, LoggerSettings.Instance, LoggerSettings.Environment, LoggerSettings.EnvironmentInstance));

                    brokeredMessages.Add(brokeredMessage);
                    sourceCommandMessages.Add(string.Format("A command was sent of type {0}.", commandType.FullName));
                }

                try
                {
                    int count = 1;
                    do
                    {
                        try
                        {
                            if (brokeredMessages.Any())
                            {
                                PrivateServiceBusPublisher.SendBatch(brokeredMessages);
                            }
                            else
                            {
                                Logger.LogDebug("An empty collection of commands to publish post validation.");
                            }
                            break;
                        }
                        catch (TimeoutException)
                        {
                            if (count >= TimeoutOnSendRetryMaximumCount)
                            {
                                throw;
                            }
                        }
                        count++;
                    } while (true);
                }
                catch (QuotaExceededException exception)
                {
                    responseCode = "429";
                    Logger.LogError("The size of the command being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Commands", sourceCommands }
                    });
                    throw;
                }
                catch (Exception exception)
                {
                    responseCode = "500";
                    Logger.LogError("An issue occurred while trying to publish a command.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Commands", sourceCommands }
                    });
                    throw;
                }

                foreach (string message in sourceCommandMessages)
                {
                    Logger.LogInfo(message);
                }

                wasSuccessfull = true;
            }
            finally
            {
                mainStopWatch.Stop();
                TelemetryHelper.TrackDependency("Azure/Servicebus/CommandBus", "Command", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
            }
        }
예제 #13
0
        /// <summary>
        /// Using a <see cref="Task"/>, clears all dead letters from the topic and subscription of the
        /// provided <paramref name="topicName"/> and <paramref name="topicSubscriptionName"/>.
        /// </summary>
        /// <param name="topicName">The name of the topic.</param>
        /// <param name="topicSubscriptionName">The name of the subscription.</param>
        /// <returns></returns>
        protected virtual CancellationTokenSource CleanUpDeadLetters(string topicName, string topicSubscriptionName)
        {
            var brokeredMessageRenewCancellationTokenSource  = new CancellationTokenSource();
            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            int lockIssues = 0;

            Action <BrokeredMessage, IMessage> leaveDeadlLetterInQueue = (deadLetterBrokeredMessage, deadLetterMessage) =>
            {
                // Remove message from queue
                try
                {
                    deadLetterBrokeredMessage.Abandon();
                    lockIssues = 0;
                }
                catch (MessageLockLostException)
                {
                    lockIssues++;
                    Logger.LogWarning(string.Format("The lock supplied for abandon for the skipped dead-letter message '{0}' is invalid.", deadLetterBrokeredMessage.MessageId));
                }
                Logger.LogDebug(string.Format("A dead-letter message of type {0} arrived with the id '{1}' but left in the queue due to settings.", deadLetterMessage.GetType().FullName, deadLetterBrokeredMessage.MessageId));
            };
            Action <BrokeredMessage> removeDeadlLetterFromQueue = deadLetterBrokeredMessage =>
            {
                // Remove message from queue
                try
                {
                    deadLetterBrokeredMessage.Complete();
                    lockIssues = 0;
                }
                catch (MessageLockLostException)
                {
                    lockIssues++;
                    Logger.LogWarning(string.Format("The lock supplied for complete for the skipped dead-letter message '{0}' is invalid.", deadLetterBrokeredMessage.MessageId));
                }
                Logger.LogDebug(string.Format("A dead-letter message arrived with the id '{0}' but was removed as processing was skipped due to settings.", deadLetterBrokeredMessage.MessageId));
            };

            Task.Factory.StartNewSafely(() =>
            {
                int loop = 0;
                while (!brokeredMessageRenewCancellationTokenSource.Token.IsCancellationRequested)
                {
                    lockIssues = 0;
                    MessagingFactory factory = MessagingFactory.CreateFromConnectionString(ConnectionString);
                    string deadLetterPath    = SubscriptionClient.FormatDeadLetterPath(topicName, topicSubscriptionName);
                    MessageReceiver client   = factory.CreateMessageReceiver(deadLetterPath, ReceiveMode.PeekLock);

                    IEnumerable <BrokeredMessage> brokeredMessages = client.ReceiveBatch(1000);

                    foreach (BrokeredMessage brokeredMessage in brokeredMessages)
                    {
                        if (lockIssues > 10)
                        {
                            break;
                        }
                        try
                        {
                            Logger.LogDebug(string.Format("A dead-letter message arrived with the id '{0}'.", brokeredMessage.MessageId));
                            string messageBody = brokeredMessage.GetBody <string>();

                            // Closure protection
                            BrokeredMessage message = brokeredMessage;
                            try
                            {
                                AzureBusHelper.ReceiveEvent
                                (
                                    messageBody,
                                    @event =>
                                {
                                    bool isRequired = BusHelper.IsEventRequired(@event.GetType());
                                    if (!isRequired)
                                    {
                                        removeDeadlLetterFromQueue(message);
                                    }
                                    else
                                    {
                                        leaveDeadlLetterInQueue(message, @event);
                                    }
                                    return(true);
                                },
                                    string.Format("id '{0}'", brokeredMessage.MessageId),
                                    () =>
                                {
                                    removeDeadlLetterFromQueue(message);
                                },
                                    () => { }
                                );
                            }
                            catch
                            {
                                AzureBusHelper.ReceiveCommand
                                (
                                    messageBody,
                                    command =>
                                {
                                    bool isRequired = BusHelper.IsEventRequired(command.GetType());
                                    if (!isRequired)
                                    {
                                        removeDeadlLetterFromQueue(message);
                                    }
                                    else
                                    {
                                        leaveDeadlLetterInQueue(message, command);
                                    }
                                    return(true);
                                },
                                    string.Format("id '{0}'", brokeredMessage.MessageId),
                                    () =>
                                {
                                    removeDeadlLetterFromQueue(message);
                                },
                                    () => { }
                                );
                            }
                        }
                        catch (Exception exception)
                        {
                            TelemetryHelper.TrackException(exception, null, telemetryProperties);
                            // Indicates a problem, unlock message in queue
                            Logger.LogError(string.Format("A dead-letter message arrived with the id '{0}' but failed to be process.", brokeredMessage.MessageId), exception: exception);
                            try
                            {
                                brokeredMessage.Abandon();
                            }
                            catch (MessageLockLostException)
                            {
                                lockIssues++;
                                Logger.LogWarning(string.Format("The lock supplied for abandon for the skipped dead-letter message '{0}' is invalid.", brokeredMessage.MessageId));
                            }
                        }
                    }

                    client.Close();

                    if (loop++ % 5 == 0)
                    {
                        loop = 0;
                        Thread.Yield();
                    }
                    else
                    {
                        Thread.Sleep(500);
                    }
                }
                try
                {
                    brokeredMessageRenewCancellationTokenSource.Dispose();
                }
                catch (ObjectDisposedException) { }
            }, brokeredMessageRenewCancellationTokenSource.Token);

            return(brokeredMessageRenewCancellationTokenSource);
        }
예제 #14
0
        /// <summary>
        /// Publishes the provided <paramref name="event"/> on the event bus.
        /// </summary>
        public virtual void Publish <TEvent>(TEvent @event)
            where TEvent : IEvent <TAuthenticationToken>
        {
            if (@event == null)
            {
                Logger.LogDebug("No event to publish.");
                return;
            }
            DateTimeOffset startedAt      = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch  = Stopwatch.StartNew();
            string         responseCode   = "200";
            bool           wasSuccessfull = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/EventHub" }
            };
            string telemetryName    = string.Format("{0}/{1}/{2}", @event.GetType().FullName, @event.GetIdentity(), @event.Id);
            var    telemeteredEvent = @event as ITelemeteredMessage;

            if (telemeteredEvent != null)
            {
                telemetryName = telemeteredEvent.TelemetryName;
            }
            telemetryName = string.Format("Event/{0}", telemetryName);

            try
            {
                if (!AzureBusHelper.PrepareAndValidateEvent(@event, "Azure-EventHub"))
                {
                    return;
                }

                try
                {
                    var brokeredMessage = new Microsoft.ServiceBus.Messaging.EventData(Encoding.UTF8.GetBytes(MessageSerialiser.SerialiseEvent(@event)));
                    brokeredMessage.Properties.Add("Type", @event.GetType().FullName);

                    EventHubPublisher.Send(brokeredMessage);
                    wasSuccessfull = true;
                }
                catch (QuotaExceededException exception)
                {
                    responseCode = "429";
                    Logger.LogError("The size of the event being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Event", @event }
                    });
                    throw;
                }
                catch (Exception exception)
                {
                    responseCode = "500";
                    Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Event", @event }
                    });
                    throw;
                }
            }
            finally
            {
                TelemetryHelper.TrackDependency("Azure/EventHub/EventBus", "Event", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
            }
            Logger.LogInfo(string.Format("An event was published with the id '{0}' was of type {1}.", @event.Id, @event.GetType().FullName));
        }
예제 #15
0
        /// <summary>
        /// Publishes the provided <paramref name="events"/> on the event bus.
        /// </summary>
        public virtual void Publish <TEvent>(IEnumerable <TEvent> events)
            where TEvent : IEvent <TAuthenticationToken>
        {
            if (events == null)
            {
                Logger.LogDebug("No events to publish.");
                return;
            }
            IList <TEvent> sourceEvents = events.ToList();

            if (!sourceEvents.Any())
            {
                Logger.LogDebug("An empty collection of events to publish.");
                return;
            }

            DateTimeOffset startedAt          = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch      = Stopwatch.StartNew();
            string         responseCode       = null;
            bool           mainWasSuccessfull = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            string telemetryName  = "Events";
            string telemetryNames = string.Empty;

            foreach (TEvent @event in sourceEvents)
            {
                Type   eventType        = @event.GetType();
                string subTelemetryName = string.Format("{0}/{1}/{2}", eventType.FullName, @event.GetIdentity(), @event.Id);
                var    telemeteredEvent = @event as ITelemeteredMessage;
                if (telemeteredEvent != null)
                {
                    subTelemetryName = telemeteredEvent.TelemetryName;
                }
                telemetryNames = string.Format("{0}{1},", telemetryNames, subTelemetryName);
            }
            if (telemetryNames.Length > 0)
            {
                telemetryNames = telemetryNames.Substring(0, telemetryNames.Length - 1);
            }
            telemetryProperties.Add("Events", telemetryNames);

            try
            {
                IList <string>          sourceEventMessages     = new List <string>();
                IList <BrokeredMessage> privateBrokeredMessages = new List <BrokeredMessage>(sourceEvents.Count);
                IList <BrokeredMessage> publicBrokeredMessages  = new List <BrokeredMessage>(sourceEvents.Count);
                foreach (TEvent @event in sourceEvents)
                {
                    if (!AzureBusHelper.PrepareAndValidateEvent(@event, "Azure-ServiceBus"))
                    {
                        continue;
                    }

                    Type eventType = @event.GetType();

                    BrokeredMessage brokeredMessage = CreateBrokeredMessage(MessageSerialiser.SerialiseEvent, eventType, @event);

                    bool?isPublicBusRequired  = BusHelper.IsPublicBusRequired(eventType);
                    bool?isPrivateBusRequired = BusHelper.IsPrivateBusRequired(eventType);

                    // Backwards compatibility and simplicity
                    if ((isPublicBusRequired == null || !isPublicBusRequired.Value) && (isPrivateBusRequired == null || !isPrivateBusRequired.Value))
                    {
                        publicBrokeredMessages.Add(brokeredMessage);
                        sourceEventMessages.Add(string.Format("An event was published on the public bus with the id '{0}' was of type {1}.", @event.Id, eventType.FullName));
                    }
                    if ((isPublicBusRequired != null && isPublicBusRequired.Value))
                    {
                        publicBrokeredMessages.Add(brokeredMessage);
                        sourceEventMessages.Add(string.Format("An event was published on the public bus with the id '{0}' was of type {1}.", @event.Id, eventType.FullName));
                    }
                    if (isPrivateBusRequired != null && isPrivateBusRequired.Value)
                    {
                        privateBrokeredMessages.Add(brokeredMessage);
                        sourceEventMessages.Add(string.Format("An event was published on the private bus with the id '{0}' was of type {1}.", @event.Id, eventType.FullName));
                    }
                }

                bool      wasSuccessfull;
                Stopwatch stopWatch = Stopwatch.StartNew();

                // Backwards compatibility and simplicity
                stopWatch.Restart();
                responseCode   = "200";
                wasSuccessfull = false;
                try
                {
                    int count = 1;
                    do
                    {
                        try
                        {
                            if (publicBrokeredMessages.Any())
                            {
#if NET452
                                PublicServiceBusPublisher.SendBatch(publicBrokeredMessages);
#endif
#if NETSTANDARD2_0
                                PublicServiceBusPublisher.SendAsync(publicBrokeredMessages).Wait();
#endif
                            }
                            else
                            {
                                Logger.LogDebug("An empty collection of public events to publish post validation.");
                            }
                            break;
                        }
                        catch (TimeoutException)
                        {
                            if (count >= TimeoutOnSendRetryMaximumCount)
                            {
                                throw;
                            }
                        }
                        count++;
                    } while (true);
                    wasSuccessfull = true;
                }
                catch (QuotaExceededException exception)
                {
                    responseCode = "429";
                    Logger.LogError("The size of the event being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Events", publicBrokeredMessages }
                    });
                    throw;
                }
                catch (Exception exception)
                {
                    responseCode = "500";
                    Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Events", publicBrokeredMessages }
                    });
                    throw;
                }
                finally
                {
                    TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, "Public Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                }

                stopWatch.Restart();
                responseCode   = "200";
                wasSuccessfull = false;
                try
                {
                    int count = 1;
                    do
                    {
                        try
                        {
                            if (privateBrokeredMessages.Any())
                            {
#if NET452
                                PrivateServiceBusPublisher.SendBatch(privateBrokeredMessages);
#endif
#if NETSTANDARD2_0
                                PrivateServiceBusPublisher.SendAsync(privateBrokeredMessages).Wait();
#endif
                            }
                            else
                            {
                                Logger.LogDebug("An empty collection of private events to publish post validation.");
                            }
                            break;
                        }
                        catch (TimeoutException)
                        {
                            if (count >= TimeoutOnSendRetryMaximumCount)
                            {
                                throw;
                            }
                        }
                        count++;
                    } while (true);
                    wasSuccessfull = true;
                }
                catch (QuotaExceededException exception)
                {
                    responseCode = "429";
                    Logger.LogError("The size of the event being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Events", privateBrokeredMessages }
                    });
                    throw;
                }
                catch (Exception exception)
                {
                    responseCode = "500";
                    Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Events", privateBrokeredMessages }
                    });
                    throw;
                }
                finally
                {
                    TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, "Private Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                }

                foreach (string message in sourceEventMessages)
                {
                    Logger.LogInfo(message);
                }

                mainWasSuccessfull = true;
            }
            finally
            {
                mainStopWatch.Stop();
                TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, mainWasSuccessfull, telemetryProperties);
            }
        }
예제 #16
0
        public static void Stop()
        {
            CancellationTokenSource.Cancel();

            TelemetryHelper.WriteEvent(TelemetryEventNames.TaskSchedulerEnd);
        }
예제 #17
0
        /// <summary>
        /// Publishes the provided <paramref name="event"/> on the event bus.
        /// </summary>
        public virtual void Publish <TEvent>(TEvent @event)
            where TEvent : IEvent <TAuthenticationToken>
        {
            if (@event == null)
            {
                Logger.LogDebug("No event to publish.");
                return;
            }
            Type           eventType          = @event.GetType();
            DateTimeOffset startedAt          = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch      = Stopwatch.StartNew();
            string         responseCode       = null;
            bool           mainWasSuccessfull = false;
            bool           telemeterOverall   = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            string telemetryName    = string.Format("{0}/{1}/{2}", eventType.FullName, @event.GetIdentity(), @event.Id);
            var    telemeteredEvent = @event as ITelemeteredMessage;

            if (telemeteredEvent != null)
            {
                telemetryName = telemeteredEvent.TelemetryName;
            }
            else
            {
                telemetryName = string.Format("Event/{0}", telemetryName);
            }

            try
            {
                if (!AzureBusHelper.PrepareAndValidateEvent(@event, "Azure-ServiceBus"))
                {
                    return;
                }

                bool?isPublicBusRequired  = BusHelper.IsPublicBusRequired(eventType);
                bool?isPrivateBusRequired = BusHelper.IsPrivateBusRequired(eventType);

                // We only add telemetry for overall operations if two occurred
                telemeterOverall = isPublicBusRequired != null && isPublicBusRequired.Value && isPrivateBusRequired != null && isPrivateBusRequired.Value;

                // Backwards compatibility and simplicity
                bool      wasSuccessfull;
                Stopwatch stopWatch = Stopwatch.StartNew();
                if ((isPublicBusRequired == null || !isPublicBusRequired.Value) && (isPrivateBusRequired == null || !isPrivateBusRequired.Value))
                {
                    stopWatch.Restart();
                    responseCode   = "200";
                    wasSuccessfull = false;
                    try
                    {
                        var brokeredMessage = CreateBrokeredMessage(MessageSerialiser.SerialiseEvent, eventType, @event);
                        int count           = 1;
                        do
                        {
                            try
                            {
#if NET452
                                PublicServiceBusPublisher.Send(brokeredMessage);
#endif
#if NETSTANDARD2_0
                                PublicServiceBusPublisher.SendAsync(brokeredMessage).Wait();
#endif
                                break;
                            }
                            catch (TimeoutException)
                            {
                                if (count >= TimeoutOnSendRetryMaximumCount)
                                {
                                    throw;
                                }
                            }
                            count++;
                        } while (true);
                        wasSuccessfull = true;
                    }
                    catch (QuotaExceededException exception)
                    {
                        responseCode = "429";
                        Logger.LogError("The size of the event being sent was too large or the topic has reached it's limit.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    catch (Exception exception)
                    {
                        responseCode = "500";
                        Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    finally
                    {
                        TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, "Default Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                    }
                    Logger.LogDebug(string.Format("An event was published on the public bus with the id '{0}' was of type {1}.", @event.Id, eventType.FullName));
                }
                if ((isPublicBusRequired != null && isPublicBusRequired.Value))
                {
                    stopWatch.Restart();
                    responseCode   = "200";
                    wasSuccessfull = false;
                    try
                    {
                        var brokeredMessage = CreateBrokeredMessage(MessageSerialiser.SerialiseEvent, eventType, @event);
                        int count           = 1;
                        do
                        {
                            try
                            {
#if NET452
                                PublicServiceBusPublisher.Send(brokeredMessage);
#endif
#if NETSTANDARD2_0
                                PublicServiceBusPublisher.SendAsync(brokeredMessage).Wait();
#endif
                                break;
                            }
                            catch (TimeoutException)
                            {
                                if (count >= TimeoutOnSendRetryMaximumCount)
                                {
                                    throw;
                                }
                            }
                            count++;
                        } while (true);
                        wasSuccessfull = true;
                    }
                    catch (QuotaExceededException exception)
                    {
                        responseCode = "429";
                        Logger.LogError("The size of the event being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    catch (Exception exception)
                    {
                        responseCode = "500";
                        Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    finally
                    {
                        TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, "Public Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                    }
                    Logger.LogDebug(string.Format("An event was published on the public bus with the id '{0}' was of type {1}.", @event.Id, eventType.FullName));
                }
                if (isPrivateBusRequired != null && isPrivateBusRequired.Value)
                {
                    stopWatch.Restart();
                    responseCode   = "200";
                    wasSuccessfull = false;
                    try
                    {
                        var brokeredMessage = CreateBrokeredMessage(MessageSerialiser.SerialiseEvent, eventType, @event);
                        int count           = 1;
                        do
                        {
                            try
                            {
#if NET452
                                PrivateServiceBusPublisher.Send(brokeredMessage);
#endif
#if NETSTANDARD2_0
                                PrivateServiceBusPublisher.SendAsync(brokeredMessage).Wait();
#endif
                                break;
                            }
                            catch (TimeoutException)
                            {
                                if (count >= TimeoutOnSendRetryMaximumCount)
                                {
                                    throw;
                                }
                            }
                            count++;
                        } while (true);
                        wasSuccessfull = true;
                    }
                    catch (QuotaExceededException exception)
                    {
                        responseCode = "429";
                        Logger.LogError("The size of the event being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    catch (Exception exception)
                    {
                        responseCode = "500";
                        Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> {
                            { "Event", @event }
                        });
                        throw;
                    }
                    finally
                    {
                        TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, "Private Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                    }

                    Logger.LogDebug(string.Format("An event was published on the private bus with the id '{0}' was of type {1}.", @event.Id, eventType.FullName));
                }
                mainWasSuccessfull = true;
            }
            finally
            {
                mainStopWatch.Stop();
                if (telemeterOverall)
                {
                    TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, mainWasSuccessfull, telemetryProperties);
                }
            }
        }
예제 #18
0
        public virtual void Publish <TCommand>(TCommand command)
            where TCommand : ICommand <TAuthenticationToken>
        {
            DateTimeOffset startedAt      = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch  = Stopwatch.StartNew();
            string         responseCode   = "200";
            bool           wasSuccessfull = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            string telemetryName      = string.Format("{0}/{1}", command.GetType().FullName, command.Id);
            var    telemeteredCommand = command as ITelemeteredMessage;

            if (telemeteredCommand != null)
            {
                telemetryName = telemeteredCommand.TelemetryName;
            }
            telemetryName = string.Format("Command/{0}", telemetryName);

            try
            {
                if (!AzureBusHelper.PrepareAndValidateCommand(command, "Azure-ServiceBus"))
                {
                    return;
                }

                try
                {
                    var brokeredMessage = new BrokeredMessage(MessageSerialiser.SerialiseCommand(command))
                    {
                        CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                    };
                    brokeredMessage.Properties.Add("Type", command.GetType().FullName);
                    PrivateServiceBusPublisher.Send(brokeredMessage);
                }
                catch (QuotaExceededException exception)
                {
                    responseCode = "429";
                    Logger.LogError("The size of the command being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Command", command }
                    });
                    throw;
                }
                catch (Exception exception)
                {
                    responseCode = "500";
                    Logger.LogError("An issue occurred while trying to publish a command.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Command", command }
                    });
                    throw;
                }

                Logger.LogInfo(string.Format("A command was sent of type {0}.", command.GetType().FullName));
                wasSuccessfull = true;
            }
            finally
            {
                mainStopWatch.Stop();
                TelemetryHelper.TrackDependency("Azure/Servicebus/CommandBus", "Command", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
            }
        }
예제 #19
0
 public void IsSonarCloud_InvalidUri_Null()
 {
     TelemetryHelper.IsSonarCloud(null).Should().BeFalse();
 }
예제 #20
0
 public ActionResult Index()
 {
     TelemetryHelper.LogVerbose(@"HomeController::Index");
     return(this.View());
 }
예제 #21
0
        protected virtual void ReceiveEvent(BrokeredMessage message)
        {
            DateTimeOffset startedAt     = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch = Stopwatch.StartNew();
            string         responseCode  = "200";
            // Null means it was skipped
            bool?wasSuccessfull = true;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            object value;

            if (message.Properties.TryGetValue("Type", out value))
            {
                telemetryProperties.Add("MessageType", value.ToString());
            }
            TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles++, telemetryProperties);
            var brokeredMessageRenewCancellationTokenSource = new CancellationTokenSource();

            try
            {
                Logger.LogDebug(string.Format("An event message arrived with the id '{0}'.", message.MessageId));
                string messageBody = message.GetBody <string>();

                IEvent <TAuthenticationToken> @event = AzureBusHelper.ReceiveEvent(messageBody, ReceiveEvent,
                                                                                   string.Format("id '{0}'", message.MessageId),
                                                                                   () =>
                {
                    wasSuccessfull = null;
                    // Remove message from queue
                    try
                    {
                        message.Complete();
                    }
                    catch (MessageLockLostException exception)
                    {
                        throw new MessageLockLostException(string.Format("The lock supplied for the skipped event message '{0}' is invalid.", message.MessageId), exception);
                    }
                    Logger.LogDebug(string.Format("An event message arrived with the id '{0}' but processing was skipped due to event settings.", message.MessageId));
                    TelemetryHelper.TrackEvent("Cqrs/Handle/Event/Skipped", telemetryProperties);
                },
                                                                                   () =>
                {
                    AzureBusHelper.RefreshLock(brokeredMessageRenewCancellationTokenSource, message, "event");
                }
                                                                                   );

                if (wasSuccessfull != null)
                {
                    // Remove message from queue
                    try
                    {
                        message.Complete();
                    }
                    catch (MessageLockLostException exception)
                    {
                        throw new MessageLockLostException(string.Format("The lock supplied for event '{0}' of type {1} is invalid.", @event.Id, @event.GetType().Name), exception);
                    }
                }
                Logger.LogDebug(string.Format("An event message arrived and was processed with the id '{0}'.", message.MessageId));

                IList <IEvent <TAuthenticationToken> > events;
                if (EventWaits.TryGetValue(@event.CorrelationId, out events))
                {
                    events.Add(@event);
                }
            }
            catch (Exception exception)
            {
                TelemetryHelper.TrackException(exception, null, telemetryProperties);
                // Indicates a problem, unlock message in queue
                Logger.LogError(string.Format("An event message arrived with the id '{0}' but failed to be process.", message.MessageId), exception: exception);
                message.Abandon();
                wasSuccessfull = false;
            }
            finally
            {
                // Cancel the lock of renewing the task
                brokeredMessageRenewCancellationTokenSource.Cancel();
                TelemetryHelper.TrackMetric("Cqrs/Handle/Event", CurrentHandles--, telemetryProperties);

                mainStopWatch.Stop();
                if (wasSuccessfull == null || !wasSuccessfull.Value)
                {
                    TelemetryHelper.TrackRequest
                    (
                        string.Format("Cqrs/Handle/Event/Skipped/{0}", message.MessageId),
                        startedAt,
                        mainStopWatch.Elapsed,
                        responseCode,
                        wasSuccessfull == null,
                        telemetryProperties
                    );
                }

                TelemetryHelper.Flush();
            }
        }
예제 #22
0
        private AventusTelemetry GetTelemetryFromStorage(IChannel channel)
        {
            var telemetryHelper = new TelemetryHelper(AccountConfig, channel);

            return(telemetryHelper.GetAventusTelemetry());
        }
예제 #23
0
        /// <summary>
        /// Receives <see cref="EventData"/> from the command bus.
        /// </summary>
        protected virtual void ReceiveCommand(PartitionContext context, EventData eventData)
        {
            DateTimeOffset startedAt     = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch = Stopwatch.StartNew();
            string         responseCode  = "200";
            // Null means it was skipped
            bool?              wasSuccessfull      = true;
            string             telemetryName       = string.Format("Cqrs/Handle/Command/{0}", eventData.SequenceNumber);
            ISingleSignOnToken authenticationToken = null;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/EventHub" }
            };
            object value;

            if (eventData.Properties.TryGetValue("Type", out value))
            {
                telemetryProperties.Add("MessageType", value.ToString());
            }
            TelemetryHelper.TrackMetric("Cqrs/Handle/Command", CurrentHandles++, telemetryProperties);
            // Do a manual 10 try attempt with back-off
            for (int i = 0; i < 10; i++)
            {
                try
                {
                    Logger.LogDebug(string.Format("A command message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset));
                    string messageBody = Encoding.UTF8.GetString(eventData.GetBytes());

                    ICommand <TAuthenticationToken> command = AzureBusHelper.ReceiveCommand(messageBody, ReceiveCommand,
                                                                                            string.Format("partition key '{0}', sequence number '{1}' and offset '{2}'", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset),
                                                                                            () =>
                    {
                        wasSuccessfull = null;
                        telemetryName  = string.Format("Cqrs/Handle/Command/Skipped/{0}", eventData.SequenceNumber);
                        responseCode   = "204";
                        // Remove message from queue
                        context.CheckpointAsync(eventData);
                        Logger.LogDebug(string.Format("A command message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but processing was skipped due to command settings.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset));
                        TelemetryHelper.TrackEvent("Cqrs/Handle/Command/Skipped", telemetryProperties);
                    }
                                                                                            );

                    if (wasSuccessfull != null)
                    {
                        if (command != null)
                        {
                            telemetryName       = string.Format("{0}/{1}", command.GetType().FullName, command.Id);
                            authenticationToken = command.AuthenticationToken as ISingleSignOnToken;

                            var telemeteredMessage = command as ITelemeteredMessage;
                            if (telemeteredMessage != null)
                            {
                                telemetryName = telemeteredMessage.TelemetryName;
                            }

                            telemetryName = string.Format("Cqrs/Handle/Command/{0}", telemetryName);
                        }
                        // Remove message from queue
                        context.CheckpointAsync(eventData);
                    }
                    Logger.LogDebug(string.Format("A command message arrived and was processed with the partition key '{0}', sequence number '{1}' and offset '{2}'.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset));

                    wasSuccessfull = true;
                    responseCode   = "200";
                    return;
                }
                catch (NoHandlersRegisteredException exception)
                {
                    TelemetryHelper.TrackException(exception, null, telemetryProperties);
                    // Indicates a problem, unlock message in queue
                    Logger.LogError(string.Format("A command message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but no handlers were found to process it.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception);
                    wasSuccessfull = false;
                    responseCode   = "501";
                    telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                    telemetryProperties.Add("ExceptionMessage", exception.Message);
                }
                catch (NoHandlerRegisteredException exception)
                {
                    TelemetryHelper.TrackException(exception, null, telemetryProperties);
                    // Indicates a problem, unlock message in queue
                    Logger.LogError(string.Format("A command message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but no handler was found to process it.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception);
                    wasSuccessfull = false;
                    responseCode   = "501";
                    telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                    telemetryProperties.Add("ExceptionMessage", exception.Message);
                }
                catch (Exception exception)
                {
                    // Indicates a problem, unlock message in queue
                    Logger.LogError(string.Format("A command message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' but failed to be process.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset), exception: exception);

                    switch (i)
                    {
                    case 0:
                    case 1:
                        // 10 seconds
                        Thread.Sleep(10 * 1000);
                        break;

                    case 2:
                    case 3:
                        // 30 seconds
                        Thread.Sleep(30 * 1000);
                        break;

                    case 4:
                    case 5:
                    case 6:
                        // 1 minute
                        Thread.Sleep(60 * 1000);
                        break;

                    case 7:
                    case 8:
                        // 3 minutes
                        Thread.Sleep(3 * 60 * 1000);
                        break;

                    case 9:
                        telemetryProperties.Add("ExceptionType", exception.GetType().FullName);
                        telemetryProperties.Add("ExceptionMessage", exception.Message);
                        break;
                    }
                    wasSuccessfull = false;
                    responseCode   = "500";
                }
                finally
                {
                    // Eventually just accept it
                    context.CheckpointAsync(eventData);

                    TelemetryHelper.TrackMetric("Cqrs/Handle/Command", CurrentHandles--, telemetryProperties);

                    mainStopWatch.Stop();
                    TelemetryHelper.TrackRequest
                    (
                        telemetryName,
                        authenticationToken,
                        startedAt,
                        mainStopWatch.Elapsed,
                        responseCode,
                        wasSuccessfull == null || wasSuccessfull.Value,
                        telemetryProperties
                    );

                    TelemetryHelper.Flush();
                }
            }
        }
        public async Task <ActionResult> Complete(OrderViewModel order)
        {
            try
            {
                // TODO: Complete the payment processing via the gateway and update the order...
                NVPAPICaller gatewayCaller = new NVPAPICaller();

                string   token = "";
                string   finalPaymentAmount = "";
                NVPCodec decoder            = new NVPCodec();

                token = Session["token"].ToString();
                //PayerID = Session["payerId"].ToString();
                //finalPaymentAmount = Session["payment_amt"].ToString();
                finalPaymentAmount = order.Total.ToString("C2");

                bool ret = gatewayCaller.DoCheckoutPayment(finalPaymentAmount, token, ref decoder);
                if (ret)
                {
                    // Retrieve PayPal confirmation value.
                    string PaymentConfirmation = decoder[NVPProperties.Properties.TRANSACTIONID].ToString();
                    order.PaymentTransactionId = PaymentConfirmation;


                    ProductContext _db = new ProductContext();
                    // Get the current order id.
                    int currentOrderId = -1;
                    if (Session["currentOrderId"] != null && Session["currentOrderId"].ToString() != string.Empty)
                    {
                        currentOrderId = Convert.ToInt32(Session["currentOrderID"]);
                    }
                    Order myCurrentOrder;
                    if (currentOrderId >= 0)
                    {
                        // Get the order based on order id.
                        myCurrentOrder = _db.Orders.Single(o => o.OrderId == currentOrderId);
                        // Update the order to reflect payment has been completed.
                        myCurrentOrder.PaymentTransactionId = PaymentConfirmation;
                        // Save to DB.
                        _db.SaveChanges();

                        // Queue up a receipt generation request, asynchronously.
                        await new AzureQueueHelper().QueueReceiptRequest(currentOrderId);

                        // Report successful event to Application Insights.
                        var eventProperties = new Dictionary <string, string>();
                        eventProperties.Add("CustomerEmail", order.Email);
                        eventProperties.Add("OrderTotal", finalPaymentAmount);
                        eventProperties.Add("PaymentTransactionId", PaymentConfirmation);
                        TelemetryHelper.TrackEvent("OrderCompleted", eventProperties);
                    }

                    // Clear shopping cart.
                    using (ShoppingCartActions usersShoppingCart =
                               new ShoppingCartActions(cartId))
                    {
                        usersShoppingCart.EmptyCart();
                    }

                    // Clear order id.
                    Session["currentOrderId"] = string.Empty;
                }
                else
                {
                    var error = gatewayCaller.PopulateGatewayErrorModel(decoder);

                    // Report failed event to Application Insights.
                    Exception ex = new Exception(error.ToString());
                    ex.Source = "Contoso.Apps.SportsLeague.Web.CheckoutController.cs";
                    TelemetryHelper.TrackException(ex);

                    // Redirect to the checkout error view:
                    return(RedirectToAction("Error", error));
                }
            }
            catch (WebException wex)
            {
                ExceptionUtility.LogException(wex, "CheckoutController.cs Complete Action");

                var error = new CheckoutErrorViewModel
                {
                    ErrorCode = wex.Message
                };

                if (wex.Response != null && wex.Response.GetType() == typeof(HttpWebResponse))
                {
                    // Extract the response body from the WebException's HttpWebResponse:
                    error.LongMessage = ((HttpWebResponse)wex.Response).StatusDescription;
                }

                // Redirect to the checkout error view:
                return(RedirectToAction("Error", error));
            }
            catch (Exception ex)
            {
                ExceptionUtility.LogException(ex, "CheckoutController.cs Complete Action");

                var error = new CheckoutErrorViewModel
                {
                    ErrorCode = ex.Message
                };

                // Redirect to the checkout error view:
                return(RedirectToAction("Error", error));
            }

            return(View(order));
        }
예제 #25
0
        protected override void InstantiateReceiving(NamespaceManager namespaceManager, IDictionary <int, SubscriptionClient> serviceBusReceivers, string topicName, string topicSubscriptionName)
        {
            base.InstantiateReceiving(namespaceManager, serviceBusReceivers, topicName, topicSubscriptionName);

            Task.Factory.StartNewSafely
                (() =>
            {
                // Because refreshing the rule can take a while, we only want to do this when the value changes
                string filter;
                if (!ConfigurationManager.TryGetSetting(FilterKeyConfigurationKey, out filter))
                {
                    return;
                }
                if (FilterKey == filter)
                {
                    return;
                }
                FilterKey = filter;

                // https://docs.microsoft.com/en-us/azure/application-insights/app-insights-analytics-reference#summarize-operator
                // http://www.summa.com/blog/business-blog/everything-you-need-to-know-about-azure-service-bus-brokered-messaging-part-2#rulesfiltersactions
                // https://github.com/Azure-Samples/azure-servicebus-messaging-samples/tree/master/TopicFilters
                SubscriptionClient client = serviceBusReceivers[0];
                bool reAddRule            = false;
                try
                {
                    IEnumerable <RuleDescription> rules = namespaceManager.GetRules(client.TopicPath, client.Name).ToList();
                    RuleDescription ruleDescription     = rules.SingleOrDefault(rule => rule.Name == "CqrsConfiguredFilter");
                    if (ruleDescription != null)
                    {
                        var sqlFilter = ruleDescription.Filter as SqlFilter;
                        if (sqlFilter == null && !string.IsNullOrWhiteSpace(filter))
                        {
                            reAddRule = true;
                        }
                        else if (sqlFilter != null && sqlFilter.SqlExpression != filter)
                        {
                            reAddRule = true;
                        }
                        if (sqlFilter != null && reAddRule)
                        {
                            client.RemoveRule("CqrsConfiguredFilter");
                        }
                    }
                    else if (!string.IsNullOrWhiteSpace(filter))
                    {
                        reAddRule = true;
                    }

                    ruleDescription = rules.SingleOrDefault(rule => rule.Name == "$Default");
                    // If there is a default rule and we have a rule, it will cause issues
                    if (!string.IsNullOrWhiteSpace(filter) && ruleDescription != null)
                    {
                        client.RemoveRule("$Default");
                    }
                    // If we don't have a rule and there is no longer a default rule, it will cause issues
                    else if (string.IsNullOrWhiteSpace(filter) && !rules.Any())
                    {
                        ruleDescription = new RuleDescription
                                          (
                            "$Default",
                            new SqlFilter("1=1")
                                          );
                        client.AddRule(ruleDescription);
                    }
                }
                catch (MessagingEntityNotFoundException)
                {
                }

                if (!reAddRule)
                {
                    return;
                }

                int loopCounter = 0;
                while (loopCounter < 10)
                {
                    try
                    {
                        RuleDescription ruleDescription = new RuleDescription
                                                          (
                            "CqrsConfiguredFilter",
                            new SqlFilter(filter)
                                                          );
                        client.AddRule(ruleDescription);
                        break;
                    }
                    catch (MessagingEntityAlreadyExistsException exception)
                    {
                        loopCounter++;
                        // Still waiting for the delete to complete
                        Thread.Sleep(1000);
                        if (loopCounter == 9)
                        {
                            Logger.LogError("Setting the filter failed as it already exists.", exception: exception);
                            TelemetryHelper.TrackException(exception);
                        }
                    }
                    catch (Exception exception)
                    {
                        Logger.LogError("Setting the filter failed.", exception: exception);
                        TelemetryHelper.TrackException(exception);
                        break;
                    }
                }
            });
        }
        public ActionResult Review(CheckoutViewModel data)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    NVPAPICaller gatewayCaller = new NVPAPICaller();

                    string   token   = "";
                    NVPCodec decoder = new NVPCodec();

                    // Call the gateway payment authorization API:
                    bool ret = gatewayCaller.DoCheckoutAuth(data.Order, ref token, ref decoder);

                    // If authorizaton is successful:
                    if (ret)
                    {
                        // Hydrate a new Order model from our OrderViewModel.
                        var myOrder = Mapper.Map <Data.Models.Order>(data.Order);
                        // Timestamp with a UTC date.
                        myOrder.OrderDate = DateTime.UtcNow;

                        // Get DB context.
                        ProductContext _db = new ProductContext();

                        // Add order to DB.
                        _db.Orders.Add(myOrder);
                        _db.SaveChanges();

                        // Get the shopping cart items and process them.
                        using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions(cartId))
                        {
                            List <CartItem> myOrderList = usersShoppingCart.GetCartItems();

                            // Add OrderDetail information to the DB for each product purchased.
                            for (int i = 0; i < myOrderList.Count; i++)
                            {
                                // Create a new OrderDetail object.
                                var myOrderDetail = new OrderDetail();
                                myOrderDetail.OrderId   = myOrder.OrderId;
                                myOrderDetail.ProductId = myOrderList[i].ProductId;
                                myOrderDetail.Quantity  = myOrderList[i].Quantity;
                                myOrderDetail.UnitPrice = myOrderList[i].Product.UnitPrice;

                                // Add OrderDetail to DB.
                                _db.OrderDetails.Add(myOrderDetail);
                                _db.SaveChanges();
                            }

                            // Set OrderId.
                            Session["currentOrderId"] = myOrder.OrderId;
                            Session["Token"]          = token;

                            // Report successful event to Application Insights.
                            var eventProperties = new Dictionary <string, string>();
                            eventProperties.Add("CustomerEmail", data.Order.Email);
                            eventProperties.Add("NumberOfItems", myOrderList.Count.ToString());
                            eventProperties.Add("OrderTotal", data.Order.Total.ToString("C2"));
                            eventProperties.Add("OrderId", myOrder.OrderId.ToString());
                            TelemetryHelper.TrackEvent("SuccessfulPaymentAuth", eventProperties);

                            data.Order.OrderId = myOrder.OrderId;
                            if (data.Order.CreditCardNumber.Length > 4)
                            {
                                // Only show the last 4 digits of the credit card number:
                                data.Order.CreditCardNumber = "xxxxxxxxxxx" + data.Order.CreditCardNumber.Substring(data.Order.CreditCardNumber.Length - 4);
                            }
                        }
                    }
                    else
                    {
                        var error = gatewayCaller.PopulateGatewayErrorModel(decoder);

                        // Report failed event to Application Insights.
                        Exception ex = new Exception(error.ToString());
                        ex.Source = "Contoso.Apps.SportsLeague.Web.CheckoutController.cs";
                        TelemetryHelper.TrackException(ex);

                        // Redirect to the checkout error view:
                        return(RedirectToAction("Error", error));
                    }
                }
                catch (WebException wex)
                {
                    ExceptionUtility.LogException(wex, "CheckoutController.cs Complete Action");

                    var error = new CheckoutErrorViewModel
                    {
                        ErrorCode = wex.Message
                    };

                    if (wex.Response != null && wex.Response.GetType() == typeof(HttpWebResponse))
                    {
                        // Extract the response body from the WebException's HttpWebResponse:
                        error.LongMessage = ((HttpWebResponse)wex.Response).StatusDescription;
                    }

                    // Redirect to the checkout error view:
                    return(RedirectToAction("Error", error));
                }
                catch (Exception ex)
                {
                    ExceptionUtility.LogException(ex, "CheckoutController.cs Review Action");

                    var error = new CheckoutErrorViewModel
                    {
                        ErrorCode = ex.Message
                    };

                    // Redirect to the checkout error view:
                    return(RedirectToAction("Error", error));
                }
            }

            return(View(data));
        }
예제 #27
0
        public virtual void Publish <TCommand>(IEnumerable <TCommand> commands)
            where TCommand : ICommand <TAuthenticationToken>
        {
            IList <TCommand> sourceCommands = commands.ToList();

            DateTimeOffset startedAt      = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch  = Stopwatch.StartNew();
            string         responseCode   = "200";
            bool           wasSuccessfull = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/EventHub" }
            };
            string telemetryName  = "Commands";
            string telemetryNames = string.Empty;

            foreach (TCommand command in sourceCommands)
            {
                string subTelemetryName   = string.Format("{0}/{1}", command.GetType().FullName, command.Id);
                var    telemeteredCommand = command as ITelemeteredMessage;
                if (telemeteredCommand != null)
                {
                    subTelemetryName = telemeteredCommand.TelemetryName;
                }
                telemetryNames = string.Format("{0}{1},", telemetryNames, subTelemetryName);
            }
            if (telemetryNames.Length > 0)
            {
                telemetryNames = telemetryNames.Substring(0, telemetryNames.Length - 1);
            }
            telemetryProperties.Add("Commands", telemetryNames);

            try
            {
                IList <string>    sourceCommandMessages = new List <string>();
                IList <EventData> brokeredMessages      = new List <EventData>(sourceCommands.Count);
                foreach (TCommand command in sourceCommands)
                {
                    if (!AzureBusHelper.PrepareAndValidateCommand(command, "Azure-EventHub"))
                    {
                        continue;
                    }

                    var brokeredMessage = new EventData(Encoding.UTF8.GetBytes(MessageSerialiser.SerialiseCommand(command)));
                    brokeredMessage.Properties.Add("Type", command.GetType().FullName);

                    brokeredMessages.Add(brokeredMessage);
                    sourceCommandMessages.Add(string.Format("A command was sent of type {0}.", command.GetType().FullName));
                }

                try
                {
                    EventHubPublisher.SendBatch(brokeredMessages);
                }
                catch (Exception exception)
                {
                    responseCode = "500";
                    Logger.LogError("An issue occurred while trying to publish a command.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Commands", sourceCommands }
                    });
                    throw;
                }

                foreach (string message in sourceCommandMessages)
                {
                    Logger.LogInfo(message);
                }

                wasSuccessfull = true;
            }
            finally
            {
                mainStopWatch.Stop();
                TelemetryHelper.TrackDependency("Azure/EventHub/CommandBus", "Command", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
            }
        }
예제 #28
0
        /// <summary>
        /// Send a feedback to telemetry server.
        /// </summary>
        /// <param name="type">Feedback type.</param>
        /// <param name="title">Feedback title.</param>
        /// <param name="content">Feedback content.</param>
        /// <param name="contactInfo">Contact information (if available)</param>
        /// <param name="image">Image (optional)</param>
        /// <returns>An awaitable task.</returns>
        public static async Task SendfeedbackAsync(FeedbackType type, string title, string content, string contactInfo,
                                                   ImageUploadResult image = null)
        {
            var currentVersion =
                $"{Package.Current.Id.Version.Major}." +
                $"{Package.Current.Id.Version.Minor}." +
                $"{Package.Current.Id.Version.Build}." +
                $"{Package.Current.Id.Version.Revision}" +
                $"_{Package.Current.Id.Architecture}";

            var osVersion = ulong.Parse(AnalyticsInfo.VersionInfo.DeviceFamilyVersion);
            var osMajor   = (osVersion & 0xFFFF000000000000L) >> 48;
            var osMinor   = (osVersion & 0x0000FFFF00000000L) >> 32;
            var osBuild   = (osVersion & 0x00000000FFFF0000L) >> 16;
            var osRev     = osVersion & 0x000000000000FFFFL;

            var feedback = new Models.Feedback
            {
                Type           = type,
                Title          = title,
                Content        = content,
                RequestId      = Guid.NewGuid(),
                RequestTimeUtc = DateTime.UtcNow,
                Runtime        = new RuntimeInfo
                {
                    ApplicationVersion = currentVersion,
                    CurrentLanguage    = CultureInfo.CurrentCulture.Name,
                    DeviceFamily       = AnalyticsInfo.VersionInfo.DeviceFamily,
                    OsReleaseVersion   = $"{osMajor}.{osMinor}.{osBuild}.{osRev}"
                },
                ContactInfo = contactInfo
            };

            if (TelemetryHelper.OptinTelemetry)
            {
                // Track an event before getting info
                await TelemetryHelper.TraceEventAsync("Feedback", new Dictionary <string, string>
                {
                    { "FeedbackId", feedback.RequestId.ToString() }
                });

                feedback.TelemetryMetadata = new ApplicationInsightInfo
                {
                    UniqueDeviceId          = TelemetryHelper.DeviceId,
                    UniqueInstrumentationId = TelemetryHelper.InstrumentationId,
                    UniqueUserId            = TelemetryHelper.UserId
                };
            }

            if (image != null)
            {
                feedback.ImageId = image.ImageId;
            }

            // Serialize request
            var requestContent = JsonConvert.SerializeObject(feedback);

            // Send request
            using (var httpClient = new HttpClient())
            {
                var uploadEndpoint = $"{RequestUrlPrefix}/api/Feedback";
                var result         = await httpClient.PostAsync(new Uri(uploadEndpoint), new HttpStringContent(
                                                                    requestContent, UnicodeEncoding.Utf8, JsonMimeType));

                // Check if request is throttled.
                if (result.StatusCode == HttpStatusCode.TooManyRequests)
                {
                    throw new RequestThrottledException();
                }
                // For other scenarios, HTTP 200 is excepted
                else if (result.StatusCode != HttpStatusCode.Ok)
                {
                    throw new FeedbackServerErrorException();
                }
            }
        }
예제 #29
0
        /// <summary>
        /// Publishes the provided <paramref name="events"/> on the event bus.
        /// </summary>
        public virtual void Publish <TEvent>(IEnumerable <TEvent> events)
            where TEvent : IEvent <TAuthenticationToken>
        {
            IList <TEvent> sourceEvents = events.ToList();

            DateTimeOffset startedAt          = DateTimeOffset.UtcNow;
            Stopwatch      mainStopWatch      = Stopwatch.StartNew();
            string         responseCode       = null;
            bool           mainWasSuccessfull = false;

            IDictionary <string, string> telemetryProperties = new Dictionary <string, string> {
                { "Type", "Azure/Servicebus" }
            };
            string telemetryName  = "Events";
            string telemetryNames = string.Empty;

            foreach (TEvent @event in sourceEvents)
            {
                string subTelemetryName = string.Format("{0}/{1}", @event.GetType().FullName, @event.Id);
                var    telemeteredEvent = @event as ITelemeteredMessage;
                if (telemeteredEvent != null)
                {
                    subTelemetryName = telemeteredEvent.TelemetryName;
                }
                telemetryNames = string.Format("{0}{1},", telemetryNames, subTelemetryName);
            }
            if (telemetryNames.Length > 0)
            {
                telemetryNames = telemetryNames.Substring(0, telemetryNames.Length - 1);
            }
            telemetryProperties.Add("Events", telemetryNames);

            try
            {
                IList <string>          sourceEventMessages     = new List <string>();
                IList <BrokeredMessage> privateBrokeredMessages = new List <BrokeredMessage>(sourceEvents.Count);
                IList <BrokeredMessage> publicBrokeredMessages  = new List <BrokeredMessage>(sourceEvents.Count);
                foreach (TEvent @event in sourceEvents)
                {
                    if (!AzureBusHelper.PrepareAndValidateEvent(@event, "Azure-ServiceBus"))
                    {
                        continue;
                    }

                    var brokeredMessage = new BrokeredMessage(MessageSerialiser.SerialiseEvent(@event))
                    {
                        CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                    };
                    brokeredMessage.Properties.Add("Type", @event.GetType().FullName);

                    var privateEventAttribute = Attribute.GetCustomAttribute(typeof(TEvent), typeof(PrivateEventAttribute)) as PrivateEventAttribute;
                    var publicEventAttribute  = Attribute.GetCustomAttribute(typeof(TEvent), typeof(PrivateEventAttribute)) as PublicEventAttribute;

                    if
                    (
                        // Backwards compatibility and simplicity
                        (publicEventAttribute == null && privateEventAttribute == null)
                        ||
                        publicEventAttribute != null
                    )
                    {
                        publicBrokeredMessages.Add(brokeredMessage);
                        sourceEventMessages.Add(string.Format("An event was published on the public bus with the id '{0}' was of type {1}.", @event.Id, @event.GetType().FullName));
                    }
                    if (privateEventAttribute != null)
                    {
                        privateBrokeredMessages.Add(brokeredMessage);
                        sourceEventMessages.Add(string.Format("An event was published on the private bus with the id '{0}' was of type {1}.", @event.Id, @event.GetType().FullName));
                    }
                }

                bool      wasSuccessfull;
                Stopwatch stopWatch = Stopwatch.StartNew();

                // Backwards compatibility and simplicity
                stopWatch.Restart();
                responseCode   = "200";
                wasSuccessfull = false;
                try
                {
                    PublicServiceBusPublisher.SendBatch(publicBrokeredMessages);
                    wasSuccessfull = true;
                }
                catch (QuotaExceededException exception)
                {
                    responseCode = "429";
                    Logger.LogError("The size of the event being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Events", publicBrokeredMessages }
                    });
                    throw;
                }
                catch (Exception exception)
                {
                    responseCode = "500";
                    Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Events", publicBrokeredMessages }
                    });
                    throw;
                }
                finally
                {
                    TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, "Public Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                }

                stopWatch.Restart();
                responseCode   = "200";
                wasSuccessfull = false;
                try
                {
                    PrivateServiceBusPublisher.SendBatch(privateBrokeredMessages);
                    wasSuccessfull = true;
                }
                catch (QuotaExceededException exception)
                {
                    responseCode = "429";
                    Logger.LogError("The size of the event being sent was too large.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Events", privateBrokeredMessages }
                    });
                    throw;
                }
                catch (Exception exception)
                {
                    responseCode = "500";
                    Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> {
                        { "Events", privateBrokeredMessages }
                    });
                    throw;
                }
                finally
                {
                    TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, "Private Bus", startedAt, stopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
                }

                foreach (string message in sourceEventMessages)
                {
                    Logger.LogInfo(message);
                }

                mainWasSuccessfull = true;
            }
            finally
            {
                mainStopWatch.Stop();
                TelemetryHelper.TrackDependency("Azure/Servicebus/EventBus", "Event", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, mainWasSuccessfull, telemetryProperties);
            }
        }
        /// <summary>
        /// Calls <see cref="AzureServiceBus{TAuthenticationToken}.InstantiateReceiving()"/>
        /// then uses a <see cref="Task"/> to apply the <see cref="FilterKey"/> as a <see cref="RuleDescription"/>
        /// to the <see cref="IMessageReceiver"/> instances in <paramref name="serviceBusReceivers"/>.
        /// </summary>
        /// <param name="manager">The <see cref="Manager"/>.</param>
        /// <param name="serviceBusReceivers">The receivers collection to place <see cref="IMessageReceiver"/> instances into.</param>
        /// <param name="topicName">The topic name.</param>
        /// <param name="topicSubscriptionName">The topic subscription name.</param>
        protected override void InstantiateReceiving(Manager manager, IDictionary <int, IMessageReceiver> serviceBusReceivers, string topicName, string topicSubscriptionName)
        {
            base.InstantiateReceiving(manager, serviceBusReceivers, topicName, topicSubscriptionName);

            Task.Factory.StartNewSafely
                (() =>
            {
                // Because refreshing the rule can take a while, we only want to do this when the value changes
                string filter;
                if (!ConfigurationManager.TryGetSetting(FilterKeyConfigurationKey, out filter))
                {
                    return;
                }
                if (FilterKey.ContainsKey(topicName) && FilterKey[topicName] == filter)
                {
                    return;
                }
                FilterKey[topicName] = filter;

                // https://docs.microsoft.com/en-us/azure/application-insights/app-insights-analytics-reference#summarize-operator
                // http://www.summa.com/blog/business-blog/everything-you-need-to-know-about-azure-service-bus-brokered-messaging-part-2#rulesfiltersactions
                // https://github.com/Azure-Samples/azure-servicebus-messaging-samples/tree/master/TopicFilters
#if NET452
                SubscriptionClient client = serviceBusReceivers[0];
#endif
#if NETSTANDARD2_0
                // Since the IMessageReceiver and it's concrete implementation doesn't allow for the management of rules, we're creating a SubscriptionClient just to do the rules... it gets cleaned up somewhat below.
                SubscriptionClient client = new SubscriptionClient(ConnectionString, topicName, topicSubscriptionName);
#endif
                bool reAddRule = false;
                try
                {
#if NET452
                    IEnumerable <RuleDescription> rules = manager.GetRules(client.TopicPath, client.Name).ToList();
#endif
#if NETSTANDARD2_0
                    Task <IList <RuleDescription> > getRulesTask = manager.GetRulesAsync(client.TopicPath, client.SubscriptionName);
                    getRulesTask.Wait();
                    IEnumerable <RuleDescription> rules = getRulesTask.Result;
#endif
                    RuleDescription ruleDescription = rules.SingleOrDefault(rule => rule.Name == "CqrsConfiguredFilter");
                    if (ruleDescription != null)
                    {
                        var sqlFilter = ruleDescription.Filter as SqlFilter;
                        if (sqlFilter == null && !string.IsNullOrWhiteSpace(filter))
                        {
                            reAddRule = true;
                        }
                        else if (sqlFilter != null && sqlFilter.SqlExpression != filter)
                        {
                            reAddRule = true;
                        }
                        if (sqlFilter != null && reAddRule)
                        {
#if NET452
                            client.RemoveRule("CqrsConfiguredFilter");
#endif
#if NETSTANDARD2_0
                            client.RemoveRuleAsync("CqrsConfiguredFilter").Wait();
#endif
                        }
                    }
                    else if (!string.IsNullOrWhiteSpace(filter))
                    {
                        reAddRule = true;
                    }

                    ruleDescription = rules.SingleOrDefault(rule => rule.Name == "$Default");
                    // If there is a default rule and we have a rule, it will cause issues
                    if (!string.IsNullOrWhiteSpace(filter) && ruleDescription != null)
                    {
#if NET452
                        client.RemoveRule("$Default");
#endif
#if NETSTANDARD2_0
                        client.RemoveRuleAsync("$Default").Wait();
#endif
                    }
                    // If we don't have a rule and there is no longer a default rule, it will cause issues
                    else if (string.IsNullOrWhiteSpace(filter) && !rules.Any())
                    {
                        ruleDescription = new RuleDescription
                                          (
                            "$Default",
                            new SqlFilter("1=1")
                                          );
#if NET452
                        client.AddRule(ruleDescription);
#endif
#if NETSTANDARD2_0
                        client.AddRuleAsync(ruleDescription).Wait();
#endif
                    }
                }
                catch (AggregateException ex)
                {
                    if (!(ex.InnerException is MessagingEntityNotFoundException))
                    {
                        throw;
                    }
                }
                catch (MessagingEntityNotFoundException)
                {
                }

                if (!reAddRule)
                {
                    return;
                }

                int loopCounter = 0;
                while (loopCounter < 10)
                {
                    try
                    {
                        RuleDescription ruleDescription = new RuleDescription
                                                          (
                            "CqrsConfiguredFilter",
                            new SqlFilter(filter)
                                                          );
#if NET452
                        client.AddRule(ruleDescription);
#endif
#if NETSTANDARD2_0
                        client.AddRuleAsync(ruleDescription).Wait();
#endif
                        break;
                    }
                    catch (MessagingEntityAlreadyExistsException exception)
                    {
                        loopCounter++;
                        // Still waiting for the delete to complete
                        Thread.Sleep(1000);
                        if (loopCounter == 9)
                        {
                            Logger.LogError("Setting the filter failed as it already exists.", exception: exception);
                            TelemetryHelper.TrackException(exception);
                        }
                    }
                    catch (Exception exception)
                    {
                        Logger.LogError("Setting the filter failed.", exception: exception);
                        TelemetryHelper.TrackException(exception);
                        break;
                    }
                }

#if NETSTANDARD2_0
                client.CloseAsync();
#endif
            });
        }