Example #1
0
        /// <summary>
        /// Publishes the provided <paramref name="event"/> on the event bus.
        /// </summary>
        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);
                }
            }
        }
Example #2
0
        public void Save_ValidEvent_EventCanBeRetreived()
        {
            // Arrange
            var correlationIdHelper = new CorrelationIdHelper(new ThreadedContextItemCollectionFactory());

            correlationIdHelper.SetCorrelationId(Guid.NewGuid());
            var logger = new ConsoleLogger(new LoggerSettings(), correlationIdHelper);

            try
            {
                // Arrange
                var connectionStringFactory = new TestMongoEventStoreConnectionStringFactory();
                TestMongoEventStoreConnectionStringFactory.DatabaseName = string.Format("Test-{0}", new Random().Next(0, 9999));

                var eventStore = new MongoDbEventStore <Guid>(new MongoDbEventBuilder <Guid>(), new MongoDbEventDeserialiser <Guid>(), logger, connectionStringFactory);

                var event1 = new TestEvent
                {
                    Rsn           = Guid.NewGuid(),
                    Id            = Guid.NewGuid(),
                    CorrelationId = correlationIdHelper.GetCorrelationId(),
                    Frameworks    = new List <string> {
                        "Test 1"
                    },
                    TimeStamp = DateTimeOffset.UtcNow
                };
                var event2 = new TestEvent
                {
                    Rsn           = Guid.NewGuid(),
                    Id            = Guid.NewGuid(),
                    CorrelationId = correlationIdHelper.GetCorrelationId(),
                    Frameworks    = new List <string> {
                        "Test 2"
                    },
                    TimeStamp = DateTimeOffset.UtcNow
                };

                // Act
                eventStore.Save <TestEvent>(event1);
                eventStore.Save <TestEvent>(event2);

                // Assert
                var timer = new Stopwatch();
                IList <IEvent <Guid> > events = eventStore.Get <TestEvent>(event1.Id).ToList();
                timer.Stop();
                Console.WriteLine("Load one operation took {0}", timer.Elapsed);
                Assert.AreEqual(1, events.Count);
                Assert.AreEqual(event1.Id, events.Single().Id);
                Assert.AreEqual(event1.Frameworks.Single(), events.Single().Frameworks.Single());

                timer.Restart();
                events = eventStore.Get <TestEvent>(event2.Id).ToList();
                timer.Stop();
                Console.WriteLine("Load one operation took {0}", timer.Elapsed);
                Assert.AreEqual(1, events.Count);
                Assert.AreEqual(event2.Id, events.Single().Id);
                Assert.AreEqual(event2.Frameworks.Single(), events.Single().Frameworks.Single());

                timer.Restart();
                IList <EventData> correlatedEvents = eventStore.Get(event1.CorrelationId).ToList();
                timer.Stop();
                Console.WriteLine("Load several correlated operation took {0}", timer.Elapsed);
                Assert.AreEqual(2, correlatedEvents.Count);
            }
            finally
            {
                // Clean-up
                TestMongoDataStoreConnectionStringFactory.DatabaseName = TestMongoEventStoreConnectionStringFactory.DatabaseName;
                var factory = new TestMongoDbDataStoreFactory(logger, new TestMongoDataStoreConnectionStringFactory());
                IMongoCollection <TestEvent> collection = factory.GetTestEventCollection();
                collection.Database.Client.DropDatabase(TestMongoDataStoreConnectionStringFactory.DatabaseName);
            }
        }
        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);
            }
        }
Example #4
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);
            }
        }
Example #5
0
        protected override void ReceiveEvent(PartitionContext context, EventData eventData)
        {
            // Do a manual 10 try attempt with back-off
            for (int i = 0; i < 10; i++)
            {
                try
                {
                    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));
                    string messageBody = Encoding.UTF8.GetString(eventData.GetBytes());
                    IEvent <TAuthenticationToken> @event = MessageSerialiser.DeserialiseEvent(messageBody);

                    CorrelationIdHelper.SetCorrelationId(@event.CorrelationId);
                    Logger.LogInfo(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' was of type {3}.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset, @event.GetType().FullName));

                    Type eventType = @event.GetType();

                    string targetQueueName = eventType.FullName;

                    try
                    {
                        object rsn = eventType.GetProperty("Rsn").GetValue(@event, null);
                        targetQueueName = string.Format("{0}.{1}", targetQueueName, rsn);
                    }
                    catch
                    {
                        Logger.LogDebug(string.Format("An event message arrived with the partition key '{0}', sequence number '{1}' and offset '{2}' was of type {3} but with no Rsn property.", eventData.PartitionKey, eventData.SequenceNumber, eventData.Offset, eventType));
                        // Do nothing if there is no rsn. Just use @event type name
                    }

                    CreateQueueAndAttachListenerIfNotExist(targetQueueName);
                    EnqueueEvent(targetQueueName, @event);

                    // remove the original message from the incoming queue
                    context.CheckpointAsync(eventData);

                    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));
                    return;
                }
                catch (Exception exception)
                {
                    // Indicates a problem, unlock message in queue
                    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);

                    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:
                    case 9:
                        // 3 minutes
                        Thread.Sleep(3 * 60 * 1000);
                        break;
                    }
                }
            }
            // Eventually just accept it
            context.CheckpointAsync(eventData);
        }
Example #6
0
        /// <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>
        {
            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);

            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", 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);
            }

            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);
        }
Example #7
0
        /// <summary>
        /// Create a <see cref="BrokeredMessage"/> with additional properties to aid routing and tracing
        /// </summary>
        protected virtual BrokeredMessage CreateBrokeredMessage <TMessage>(Func <TMessage, string> serialiserFunction, Type messageType, TMessage message)
        {
            string messageBody = serialiserFunction(message);

#if NET452
            var brokeredMessage = new BrokeredMessage(messageBody)
#endif
#if NETSTANDARD2_0
            byte[] messageBodyData;
            using (var stream = new MemoryStream())
            {
                brokeredMessageSerialiser.WriteObject(stream, messageBody);
                stream.Flush();
                stream.Position = 0;
                messageBodyData = stream.ToArray();
            }

            var brokeredMessage = new BrokeredMessage(messageBodyData)
#endif
            {
                CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
            };
            brokeredMessage.AddUserProperty("CorrelationId", brokeredMessage.CorrelationId);
            brokeredMessage.AddUserProperty("Type", messageType.FullName);
            brokeredMessage.AddUserProperty("Source", string.Format("{0}/{1}/{2}/{3}", Logger.LoggerSettings.ModuleName, Logger.LoggerSettings.Instance, Logger.LoggerSettings.Environment, Logger.LoggerSettings.EnvironmentInstance));
#if NET452
            brokeredMessage.AddUserProperty("Framework", ".NET Framework");
#else
            brokeredMessage.AddUserProperty("Framework", ".NET Core");
#endif

            // see https://github.com/Chinchilla-Software-Com/CQRS/wiki/Inter-process-function-security</remarks>
            string        configurationKey = string.Format("{0}.SigningToken", messageType.FullName);
            string        signingToken;
            HashAlgorithm signer = Signer.Create();
            if (!ConfigurationManager.TryGetSetting(configurationKey, out signingToken) || string.IsNullOrWhiteSpace(signingToken))
            {
                if (!ConfigurationManager.TryGetSetting(SigningTokenConfigurationKey, out signingToken) || string.IsNullOrWhiteSpace(signingToken))
                {
                    signingToken = Guid.Empty.ToString("N");
                }
            }
            if (!string.IsNullOrWhiteSpace(signingToken))
            {
                using (var hashStream = new MemoryStream(Encoding.UTF8.GetBytes($"{signingToken}{messageBody}")))
                    brokeredMessage.AddUserProperty("Signature", Convert.ToBase64String(signer.ComputeHash(hashStream)));
            }

            try
            {
                var          stackTrace  = new StackTrace();
                StackFrame[] stackFrames = stackTrace.GetFrames();
                if (stackFrames != null)
                {
                    foreach (StackFrame frame in stackFrames)
                    {
                        MethodBase method = frame.GetMethod();
                        if (method.ReflectedType == null)
                        {
                            continue;
                        }

                        try
                        {
                            if (ExclusionNamespaces.All(@namespace => !method.ReflectedType.FullName.StartsWith(@namespace)))
                            {
                                brokeredMessage.AddUserProperty("Source-Method", string.Format("{0}.{1}", method.ReflectedType.FullName, method.Name));
                                break;
                            }
                        }
                        catch
                        {
                            // Just move on
                        }
                    }
                }
            }
            catch
            {
                // Just move on
            }

            return(brokeredMessage);
        }
 protected virtual TServiceResponse CompleteResponse <TServiceResponse>(TServiceResponse serviceResponse)
     where TServiceResponse : IServiceResponse
 {
     serviceResponse.CorrelationId = CorrelationIdHelper.GetCorrelationId();
     return(serviceResponse);
 }
Example #9
0
        public virtual ICommand <TAuthenticationToken> ReceiveCommand(string messageBody, Action <ICommand <TAuthenticationToken> > receiveCommandHandler, string messageId, Action skippedAction = null, Action lockRefreshAction = null)
        {
            ICommand <TAuthenticationToken> command;

            try
            {
                command = MessageSerialiser.DeserialiseCommand(messageBody);
            }
            catch (JsonSerializationException exception)
            {
                JsonSerializationException checkException = exception;
                bool safeToExit = false;
                do
                {
                    if (checkException.Message.StartsWith("Could not load assembly"))
                    {
                        safeToExit = true;
                        break;
                    }
                } while ((checkException = checkException.InnerException as JsonSerializationException) != null);
                if (safeToExit)
                {
                    const string pattern = @"(?<=^Error resolving type specified in JSON ').+?(?='\. Path '\$type')";
                    Match        match   = new Regex(pattern).Match(exception.Message);
                    if (match.Success)
                    {
                        string[] typeParts = match.Value.Split(',');
                        if (typeParts.Length == 2)
                        {
                            string classType  = typeParts[0];
                            bool   isRequired = BusHelper.IsEventRequired(string.Format("{0}.IsRequired", classType));

                            if (!isRequired)
                            {
                                if (skippedAction != null)
                                {
                                    skippedAction();
                                }
                                return(null);
                            }
                        }
                    }
                }
                throw;
            }

            string commandTypeName = command.GetType().FullName;

            CorrelationIdHelper.SetCorrelationId(command.CorrelationId);
            Logger.LogInfo(string.Format("A command message arrived with the {0} was of type {1}.", messageId, commandTypeName));

            bool canRefresh;

            if (!ConfigurationManager.TryGetSetting(string.Format("{0}.ShouldRefresh", commandTypeName), out canRefresh))
            {
                canRefresh = false;
            }

            if (canRefresh)
            {
                if (lockRefreshAction == null)
                {
                    Logger.LogWarning(string.Format("A command message arrived with the {0} was of type {1} and was destined to support lock renewal, but no action was provided.", messageId, commandTypeName));
                }
                else
                {
                    lockRefreshAction();
                }
            }

            receiveCommandHandler(command);

            return(command);
        }
Example #10
0
        /// <summary>
        /// Publishes the provided <paramref name="event"/> on the event bus.
        /// </summary>
        public virtual void Publish <TEvent>(TEvent @event)
            where TEvent : IEvent <TAuthenticationToken>
        {
            Type   eventType = @event.GetType();
            string eventName = eventType.FullName;
            ISagaEvent <TAuthenticationToken> sagaEvent = @event as ISagaEvent <TAuthenticationToken>;

            if (sagaEvent != null)
            {
                eventName = string.Format("Cqrs.Events.SagaEvent[{0}]", sagaEvent.Event.GetType().FullName);
            }

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

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

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

            try
            {
                if (@event.Frameworks != null && @event.Frameworks.Contains("Built-In"))
                {
                    Logger.LogInfo("The provided event has already been processed by the Built-In bus.", string.Format("{0}\\PrepareAndValidateEvent({1})", GetType().FullName, eventType.FullName));
                    return;
                }

                if (@event.AuthenticationToken == null || @event.AuthenticationToken.Equals(default(TAuthenticationToken)))
                {
                    @event.AuthenticationToken = AuthenticationTokenHelper.GetAuthenticationToken();
                }
                @event.CorrelationId = CorrelationIdHelper.GetCorrelationId();

                if (string.IsNullOrWhiteSpace(@event.OriginatingFramework))
                {
                    @event.TimeStamp            = DateTimeOffset.UtcNow;
                    @event.OriginatingFramework = "Built-In";
                }

                var frameworks = new List <string>();
                if (@event.Frameworks != null)
                {
                    frameworks.AddRange(@event.Frameworks);
                }
                frameworks.Add("Built-In");
                @event.Frameworks = frameworks;

                bool isRequired;
                if (!ConfigurationManager.TryGetSetting(string.Format("{0}.IsRequired", eventName), out isRequired))
                {
                    isRequired = true;
                }

                IEnumerable <Action <IMessage> > handlers = Routes.GetHandlers(@event, isRequired).Select(x => x.Delegate).ToList();
                // This check doesn't require an isRequired check as there will be an exception raised above and handled below.
                if (!handlers.Any())
                {
                    Logger.LogDebug(string.Format("An event handler for '{0}' is not required.", eventName));
                }

                foreach (Action <IMessage> handler in handlers)
                {
                    IList <IEvent <TAuthenticationToken> > events;
                    if (EventWaits.TryGetValue(@event.CorrelationId, out events))
                    {
                        events.Add(@event);
                    }
                    handler(@event);
                }

                Logger.LogInfo(string.Format("An event was sent of type {0}.", eventName));
                wasSuccessfull = true;
            }
            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
            {
                mainStopWatch.Stop();
                TelemetryHelper.TrackDependency("InProcessBus/EventBus", "Event", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties);
            }
        }
Example #11
0
        protected virtual void ReceiveEvent(BrokeredMessage message)
        {
            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;

                try
                {
                    @event = MessageSerialiser.DeserialiseEvent(messageBody);
                }
                catch (JsonSerializationException exception)
                {
                    JsonSerializationException checkException = exception;
                    bool safeToExit = false;
                    do
                    {
                        if (checkException.Message.StartsWith("Could not load assembly"))
                        {
                            safeToExit = true;
                            break;
                        }
                    } while ((checkException = checkException.InnerException as JsonSerializationException) != null);
                    if (safeToExit)
                    {
                        const string pattern = @"(?<=^Error resolving type specified in JSON ').+?(?='\. Path '\$type')";
                        Match        match   = new Regex(pattern).Match(exception.Message);
                        if (match.Success)
                        {
                            string[] typeParts = match.Value.Split(',');
                            if (typeParts.Length == 2)
                            {
                                string classType = typeParts[0];
                                bool   isRequired;
                                if (!ConfigurationManager.TryGetSetting(string.Format("{0}.IsRequired", classType), out isRequired))
                                {
                                    isRequired = true;
                                }

                                if (!isRequired)
                                {
                                    // Remove message from queue
                                    message.Complete();
                                    Logger.LogDebug(string.Format("An event message arrived with the id '{0}' but processing was skipped due to event settings.", message.MessageId));
                                    return;
                                }
                            }
                        }
                    }
                    throw;
                }

                CorrelationIdHelper.SetCorrelationId(@event.CorrelationId);
                Logger.LogInfo(string.Format("An event message arrived with the id '{0}' was of type {1}.", message.MessageId, @event.GetType().FullName));

                bool canRefresh;
                if (!ConfigurationManager.TryGetSetting(string.Format("{0}.ShouldRefresh", @event.GetType().FullName), out canRefresh))
                {
                    canRefresh = false;
                }

                if (canRefresh)
                {
                    Task.Factory.StartNew(() =>
                    {
                        while (!brokeredMessageRenewCancellationTokenSource.Token.IsCancellationRequested)
                        {
                            //Based on LockedUntilUtc property to determine if the lock expires soon
                            if (DateTime.UtcNow > message.LockedUntilUtc.AddSeconds(-10))
                            {
                                // If so, repeat the message
                                message.RenewLock();
                            }

                            Thread.Sleep(500);
                        }
                    }, brokeredMessageRenewCancellationTokenSource.Token);
                }

                ReceiveEvent(@event);

                // Remove message from queue
                message.Complete();
                Logger.LogDebug(string.Format("An event message arrived and was processed with the id '{0}'.", message.MessageId));
            }
            catch (Exception exception)
            {
                // 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();
            }
            finally
            {
                // Cancel the lock of renewing the task
                brokeredMessageRenewCancellationTokenSource.Cancel();
            }
        }
        protected virtual void ReceiveCommand(BrokeredMessage message)
        {
            try
            {
                Logger.LogDebug(string.Format("A command message arrived with the id '{0}'.", message.MessageId));
                string messageBody = message.GetBody <string>();
                ICommand <TAuthenticationToken> command;
                try
                {
                    command = MessageSerialiser.DeserialiseCommand(messageBody);
                }
                catch (JsonSerializationException exception)
                {
                    JsonSerializationException checkException = exception;
                    bool safeToExit = false;
                    do
                    {
                        if (checkException.Message.StartsWith("Could not load assembly"))
                        {
                            safeToExit = true;
                            break;
                        }
                    } while ((checkException = checkException.InnerException as JsonSerializationException) != null);
                    if (safeToExit)
                    {
                        const string pattern = @"(?<=^Error resolving type specified in JSON ').+?(?='\. Path '\$type')";
                        Match        match   = new Regex(pattern).Match(exception.Message);
                        if (match.Success)
                        {
                            string[] typeParts = match.Value.Split(',');
                            if (typeParts.Length == 2)
                            {
                                string classType  = typeParts[0];
                                bool   isRequired = BusHelper.IsEventRequired(classType);

                                if (!isRequired)
                                {
                                    // Remove message from queue
                                    message.Complete();
                                    Logger.LogDebug(string.Format("A command message arrived with the id '{0}' but processing was skipped due to command settings.", message.MessageId));
                                    return;
                                }
                            }
                        }
                    }
                    throw;
                }

                CorrelationIdHelper.SetCorrelationId(command.CorrelationId);
                Logger.LogInfo(string.Format("A command message arrived with the id '{0}' was of type {1}.", message.MessageId, command.GetType().FullName));

                ReceiveCommand(command);

                // Remove message from queue
                message.Complete();
                Logger.LogDebug(string.Format("A command message arrived and was processed with the id '{0}'.", message.MessageId));
            }
            catch (Exception exception)
            {
                // 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();
            }
        }
Example #13
0
        /// <summary>
        /// Create a <see cref="BrokeredMessage"/> with additional properties to aid routing and tracing
        /// </summary>
        protected virtual BrokeredMessage CreateBrokeredMessage <TMessage>(Func <TMessage, string> serialiserFunction, Type messageType, TMessage message)
        {
            string messageBody     = serialiserFunction(message);
            var    brokeredMessage = new BrokeredMessage(messageBody)
            {
                CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
            };

            brokeredMessage.Properties.Add("Type", messageType.FullName);
            brokeredMessage.Properties.Add("Source", string.Format("{0}/{1}/{2}/{3}", LoggerSettings.ModuleName, LoggerSettings.Instance, LoggerSettings.Environment, LoggerSettings.EnvironmentInstance));

            // see https://github.com/Chinchilla-Software-Com/CQRS/wiki/Inter-process-function-security</remarks>
            string configurationKey = string.Format("{0}.SigningToken", messageType.FullName);
            string signingToken;

            if (!ConfigurationManager.TryGetSetting(configurationKey, out signingToken) || string.IsNullOrWhiteSpace(signingToken))
            {
                if (!ConfigurationManager.TryGetSetting(SigningTokenConfigurationKey, out signingToken) || string.IsNullOrWhiteSpace(signingToken))
                {
                    signingToken = Guid.Empty.ToString("N");
                }
            }
            if (!string.IsNullOrWhiteSpace(signingToken))
            {
                using (var hashStream = new MemoryStream(Encoding.UTF8.GetBytes(string.Concat("{0}{1}", signingToken, messageBody))))
                    brokeredMessage.Properties.Add("Signature", Convert.ToBase64String(Signer.ComputeHash(hashStream)));
            }

            try
            {
                var          stackTrace  = new StackTrace();
                StackFrame[] stackFrames = stackTrace.GetFrames();
                if (stackFrames != null)
                {
                    foreach (StackFrame frame in stackFrames)
                    {
                        MethodBase method = frame.GetMethod();
                        if (method.ReflectedType == null)
                        {
                            continue;
                        }

                        try
                        {
                            if (ExclusionNamespaces.All(@namespace => !method.ReflectedType.FullName.StartsWith(@namespace)))
                            {
                                brokeredMessage.Properties.Add("Source-Method", string.Format("{0}.{1}", method.ReflectedType.FullName, method.Name));
                                break;
                            }
                        }
                        catch
                        {
                            // Just move on
                        }
                    }
                }
            }
            catch
            {
                // Just move on
            }

            return(brokeredMessage);
        }
Example #14
0
        protected virtual void DequeuAndProcessCommand(string queueName)
        {
            long loop = long.MinValue;

            while (true)
            {
                try
                {
                    ConcurrentQueue <ICommand <TAuthenticationToken> > queue;
                    if (QueueTracker.TryGetValue(queueName, out queue))
                    {
                        while (!queue.IsEmpty)
                        {
                            ICommand <TAuthenticationToken> command;
                            if (queue.TryDequeue(out command))
                            {
                                try
                                {
                                    CorrelationIdHelper.SetCorrelationId(command.CorrelationId);
                                }
                                catch (Exception exception)
                                {
                                    Logger.LogError(string.Format("Trying to set the CorrelationId from the command type {1} for a request for the queue '{0}' failed.", queueName, command.GetType()), exception: exception);
                                }
                                try
                                {
                                    AuthenticationTokenHelper.SetAuthenticationToken(command.AuthenticationToken);
                                }
                                catch (Exception exception)
                                {
                                    Logger.LogError(string.Format("Trying to set the AuthenticationToken from the command type {1} for a request for the queue '{0}' failed.", queueName, command.GetType()), exception: exception);
                                }
                                try
                                {
                                    ReceiveCommand(command);
                                }
                                catch (Exception exception)
                                {
                                    Logger.LogError(string.Format("Processing the command type {1} for a request for the queue '{0}' failed.", queueName, command.GetType()), exception: exception);
                                    queue.Enqueue(command);
                                }
                            }
                            else
                            {
                                Logger.LogDebug(string.Format("Trying to dequeue a command from the queue '{0}' failed.", queueName));
                            }
                        }
                    }
                    else
                    {
                        Logger.LogDebug(string.Format("Trying to find the queue '{0}' failed.", queueName));
                    }

                    if (loop++ % 5 == 0)
                    {
                        Thread.Yield();
                    }
                    else
                    {
                        Thread.Sleep(100);
                    }
                    if (loop == long.MaxValue)
                    {
                        loop = long.MinValue;
                    }
                }
                catch (Exception exception)
                {
                    Logger.LogError(string.Format("Dequeuing and processing a request for the queue '{0}' failed.", queueName), exception: exception);
                }
            }
        }
Example #15
0
        /// <summary>
        /// Send out an event to specific user RSNs
        /// </summary>
        void INotificationHub.SendUsersEvent <TSingleSignOnToken>(IEvent <TSingleSignOnToken> eventData, params Guid[] userRsnCollection)
        {
            IList <Guid> optimisedUserRsnCollection = (userRsnCollection ?? Enumerable.Empty <Guid>()).ToList();

            Logger.LogDebug(string.Format("Sending a message on the hub for user RSNs [{0}].", string.Join(", ", optimisedUserRsnCollection)));

            try
            {
                var tokenSource = new CancellationTokenSource();
                Task.Factory.StartNewSafely
                (
                    () =>
                {
                    foreach (Guid userRsn in optimisedUserRsnCollection)
                    {
                        var metaData = GetAdditionalDataForLogging(userRsn);
                        try
                        {
                            Clients
                            .Group(string.Format("UserRsn-{0}", userRsn))
                            .notifyEvent(new { Type = eventData.GetType().FullName, Data = eventData, CorrelationId = CorrelationIdHelper.GetCorrelationId() });
                        }
                        catch (TimeoutException exception)
                        {
                            Logger.LogWarning("Sending a message on the hub timed-out.", exception: exception, metaData: metaData);
                        }
                        catch (Exception exception)
                        {
                            Logger.LogError("Sending a message on the hub resulted in an error.", exception: exception, metaData: metaData);
                        }
                    }
                }, tokenSource.Token
                );

                tokenSource.CancelAfter(15 * 1000);
            }
            catch (Exception exception)
            {
                foreach (Guid userRsn in optimisedUserRsnCollection)
                {
                    Logger.LogError("Queueing a message on the hub resulted in an error.", exception: exception, metaData: GetAdditionalDataForLogging(userRsn));
                }
            }
        }
Example #16
0
        public virtual IEvent <TAuthenticationToken> ReceiveEvent(string messageBody, Func <IEvent <TAuthenticationToken>, bool?> receiveEventHandler, string messageId, Action skippedAction = null, Action lockRefreshAction = null)
        {
            IEvent <TAuthenticationToken> @event;

            try
            {
                @event = MessageSerialiser.DeserialiseEvent(messageBody);
            }
            catch (JsonSerializationException exception)
            {
                JsonSerializationException checkException = exception;
                bool safeToExit = false;
                do
                {
                    if (checkException.Message.StartsWith("Could not load assembly"))
                    {
                        safeToExit = true;
                        break;
                    }
                } while ((checkException = checkException.InnerException as JsonSerializationException) != null);
                if (safeToExit)
                {
                    const string pattern = @"(?<=^Error resolving type specified in JSON ').+?(?='\. Path '\$type')";
                    Match        match   = new Regex(pattern).Match(exception.Message);
                    if (match.Success)
                    {
                        string[] typeParts = match.Value.Split(',');
                        if (typeParts.Length == 2)
                        {
                            string classType  = typeParts[0];
                            bool   isRequired = BusHelper.IsEventRequired(string.Format("{0}.IsRequired", classType));

                            if (!isRequired)
                            {
                                if (skippedAction != null)
                                {
                                    skippedAction();
                                }
                                return(null);
                            }
                        }
                    }
                }
                throw;
            }

            string eventTypeName = @event.GetType().FullName;

            CorrelationIdHelper.SetCorrelationId(@event.CorrelationId);
            AuthenticationTokenHelper.SetAuthenticationToken(@event.AuthenticationToken);
            Logger.LogInfo(string.Format("An event message arrived with the {0} was of type {1}.", messageId, eventTypeName));

            bool canRefresh;

            if (!ConfigurationManager.TryGetSetting(string.Format("{0}.ShouldRefresh", eventTypeName), out canRefresh))
            {
                canRefresh = false;
            }

            if (canRefresh)
            {
                if (lockRefreshAction == null)
                {
                    Logger.LogWarning(string.Format("An event message arrived with the {0} was of type {1} and was destined to support lock renewal, but no action was provided.", messageId, eventTypeName));
                }
                else
                {
                    lockRefreshAction();
                }
            }

            // a false response means the action wasn't handled, but didn't throw an error, so we assume, by convention, that this means it was skipped.
            bool?result = receiveEventHandler(@event);

            if (result != null && !result.Value)
            {
                if (skippedAction != null)
                {
                    skippedAction();
                }
            }

            return(@event);
        }
Example #17
0
        /// <summary>
        /// Send out an event to specific user token
        /// </summary>
        void INotificationHub.SendUserEvent <TSingleSignOnToken>(IEvent <TSingleSignOnToken> eventData, string userToken)
        {
            Logger.LogDebug(string.Format("Sending a message on the hub for user [{0}].", userToken));

            try
            {
                var tokenSource = new CancellationTokenSource();
                Task.Factory.StartNewSafely
                (
                    () =>
                {
                    IDictionary <string, object> metaData = GetAdditionalDataForLogging(userToken);

                    try
                    {
                        CurrentHub
                        .Clients
                        .Group(string.Format("User-{0}", userToken))
                        .notifyEvent(new { Type = eventData.GetType().FullName, Data = eventData, CorrelationId = CorrelationIdHelper.GetCorrelationId() });
                    }
                    catch (TimeoutException exception)
                    {
                        Logger.LogWarning("Sending a message on the hub timed-out.", exception: exception, metaData: metaData);
                    }
                    catch (Exception exception)
                    {
                        Logger.LogError("Sending a message on the hub resulted in an error.", exception: exception, metaData: metaData);
                    }
                }, tokenSource.Token
                );

                tokenSource.CancelAfter(15 * 1000);
            }
            catch (Exception exception)
            {
                Logger.LogError("Queueing a message on the hub resulted in an error.", exception: exception, metaData: GetAdditionalDataForLogging(userToken));
            }
        }
Example #18
0
        protected void DequeuAndProcessEvent(string queueName)
        {
            SpinWait.SpinUntil
            (
                () =>
            {
                try
                {
                    ConcurrentQueue <IEvent <TAuthenticationToken> > queue;
                    if (QueueTracker.TryGetValue(queueName, out queue))
                    {
                        while (!queue.IsEmpty)
                        {
                            IEvent <TAuthenticationToken> @event;
                            if (queue.TryDequeue(out @event))
                            {
                                try
                                {
                                    CorrelationIdHelper.SetCorrelationId(@event.CorrelationId);
                                }
                                catch (Exception exception)
                                {
                                    Logger.LogError(string.Format("Trying to set the CorrelationId from the event type {1} for a request for the queue '{0}' failed.", queueName, @event.GetType()), exception: exception);
                                }
                                try
                                {
                                    AuthenticationTokenHelper.SetAuthenticationToken(@event.AuthenticationToken);
                                }
                                catch (Exception exception)
                                {
                                    Logger.LogError(string.Format("Trying to set the AuthenticationToken from the event type {1} for a request for the queue '{0}' failed.", queueName, @event.GetType()), exception: exception);
                                }
                                try
                                {
                                    ReceiveEvent(@event);
                                }
                                catch (Exception exception)
                                {
                                    Logger.LogError(string.Format("Processing the event type {1} for a request for the queue '{0}' failed.", queueName, @event.GetType()), exception: exception);
                                    queue.Enqueue(@event);
                                }
                            }
                            else
                            {
                                Logger.LogDebug(string.Format("Trying to dequeue a event from the queue '{0}' failed.", queueName));
                            }
                        }
                    }
                    else
                    {
                        Logger.LogDebug(string.Format("Trying to find the queue '{0}' failed.", queueName));
                    }
                    Thread.Sleep(100);
                }
                catch (Exception exception)
                {
                    Logger.LogError(string.Format("Dequeuing and processing a request for the queue '{0}' failed.", queueName), exception: exception);
                }

                // Always return false to keep this spinning.
                return(false);
            },
                sleepInMilliseconds: 1000
            );
        }
Example #19
0
        /// <summary>
        /// Send out an event to all users
        /// </summary>
        void INotificationHub.SendAllUsersEvent <TSingleSignOnToken>(IEvent <TSingleSignOnToken> eventData)
        {
            Logger.LogDebug("Sending a message on the hub to all users.");

            try
            {
                var tokenSource = new CancellationTokenSource();
                Task.Factory.StartNewSafely
                (
                    () =>
                {
                    try
                    {
                        CurrentHub
                        .Clients
                        .All
                        .notifyEvent(new { Type = eventData.GetType().FullName, Data = eventData, CorrelationId = CorrelationIdHelper.GetCorrelationId() });
                    }
                    catch (TimeoutException exception)
                    {
                        Logger.LogWarning("Sending a message on the hub to all users timed-out.", exception: exception);
                    }
                    catch (Exception exception)
                    {
                        Logger.LogError("Sending a message on the hub to all users resulted in an error.", exception: exception);
                    }
                }, tokenSource.Token
                );

                tokenSource.CancelAfter(15 * 1000);
            }
            catch (Exception exception)
            {
                Logger.LogError("Queueing a message on the hub to all users resulted in an error.", exception: exception);
            }
        }
Example #20
0
        /// <summary>
        /// Publishes the provided <paramref name="commands"/> on the command bus.
        /// </summary>
        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/Servicebus" }
            };
            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 <BrokeredMessage> brokeredMessages      = new List <BrokeredMessage>(sourceCommands.Count);
                foreach (TCommand command in sourceCommands)
                {
                    if (!AzureBusHelper.PrepareAndValidateCommand(command, "Azure-ServiceBus"))
                    {
                        continue;
                    }

                    var brokeredMessage = new BrokeredMessage(MessageSerialiser.SerialiseCommand(command))
                    {
                        CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                    };
                    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
                {
                    PrivateServiceBusPublisher.SendBatch(brokeredMessages);
                }
                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);
            }
        }
Example #21
0
        /// <summary>
        /// Save and persist the provided <paramref name="aggregate"/>, optionally providing the version number the <see cref="IAggregateRoot{TAuthenticationToken}"/> is expected to be at.
        /// </summary>
        /// <typeparam name="TAggregateRoot">The <see cref="Type"/> of the <see cref="IAggregateRoot{TAuthenticationToken}"/>.</typeparam>
        /// <param name="aggregate">The <see cref="IAggregateRoot{TAuthenticationToken}"/> to save and persist.</param>
        /// <param name="expectedVersion">The version number the <see cref="IAggregateRoot{TAuthenticationToken}"/> is expected to be at.</param>
        public virtual void Save <TAggregateRoot>(TAggregateRoot aggregate, int?expectedVersion = null)
            where TAggregateRoot : IAggregateRoot <TAuthenticationToken>
        {
            IList <IEvent <TAuthenticationToken> > uncommittedChanges = aggregate.GetUncommittedChanges().ToList();

            if (!uncommittedChanges.Any())
            {
                return;
            }

            if (expectedVersion != null)
            {
                IEnumerable <IEvent <TAuthenticationToken> > eventStoreResults = EventStore.Get(aggregate.GetType(), aggregate.Id, false, expectedVersion.Value);
                if (eventStoreResults.Any())
                {
                    throw new ConcurrencyException(aggregate.Id);
                }
            }

            var eventsToPublish = new List <IEvent <TAuthenticationToken> >();

            int i       = 0;
            int version = aggregate.Version;

            foreach (IEvent <TAuthenticationToken> @event in uncommittedChanges)
            {
                var eventWithIdentity = @event as IEventWithIdentity <TAuthenticationToken>;
                if (eventWithIdentity != null)
                {
                    if (eventWithIdentity.Rsn == Guid.Empty)
                    {
                        eventWithIdentity.Rsn = aggregate.Id;
                    }
                    if (eventWithIdentity.Rsn == Guid.Empty)
                    {
                        throw new AggregateOrEventMissingIdException(aggregate.GetType(), @event.GetType());
                    }
                }
                else
                {
                    if (@event.Id == Guid.Empty)
                    {
                        @event.Id = aggregate.Id;
                    }
                    if (@event.Id == Guid.Empty)
                    {
                        throw new AggregateOrEventMissingIdException(aggregate.GetType(), @event.GetType());
                    }
                }

                i++;
                version++;

                @event.Version       = version;
                @event.TimeStamp     = DateTimeOffset.UtcNow;
                @event.CorrelationId = CorrelationIdHelper.GetCorrelationId();
                EventStore.Save(aggregate.GetType(), @event);
                eventsToPublish.Add(@event);
            }

            aggregate.MarkChangesAsCommitted();
            foreach (IEvent <TAuthenticationToken> @event in eventsToPublish)
            {
                PublishEvent(@event);
            }
        }
Example #22
0
        /// <summary>
        /// Publishes the provided <paramref name="command"/> on the command bus.
        /// </summary>
        public virtual void Publish <TCommand>(TCommand command)
            where TCommand : ICommand <TAuthenticationToken>
        {
            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}", command.GetType().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;
                }

                Type commandType          = typeof(TCommand);
                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.GetType().FullName);
                        PublicServiceBusPublisher.Send(brokeredMessage);
                        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, command.GetType().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.GetType().FullName);
                        PublicServiceBusPublisher.Send(brokeredMessage);
                        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, command.GetType().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", command.GetType().FullName);
                        PrivateServiceBusPublisher.Send(brokeredMessage);
                        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, command.GetType().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="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 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.SerialiseEvent(@event))
                        {
                            CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                        };
                        brokeredMessage.Properties.Add("Type", eventType.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 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 = new BrokeredMessage(MessageSerialiser.SerialiseEvent(@event))
                        {
                            CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                        };
                        brokeredMessage.Properties.Add("Type", eventType.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 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 = new BrokeredMessage(MessageSerialiser.SerialiseEvent(@event))
                        {
                            CorrelationId = CorrelationIdHelper.GetCorrelationId().ToString("N")
                        };
                        brokeredMessage.Properties.Add("Type", eventType.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 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);
                }
            }
        }