public async Task PublishAsync <T>(T input, string topic, TimeSpan?initialVisibilityDelay = null) where T : class
        {
            var newContext = new AFBusMessageContext();

            newContext.MessageID         = Guid.NewGuid();
            newContext.TransactionID     = Context.TransactionID ?? Guid.NewGuid();
            newContext.BodyType          = typeof(T).AssemblyQualifiedName;
            newContext.BodyInFile        = false;
            newContext.Destination       = topic;
            newContext.SenderServiceName = Context.ActualServiceName;

            if (initialVisibilityDelay != null)
            {
                newContext.MessageDelayedTime          = initialVisibilityDelay;
                newContext.MessageFinalWakeUpTimeStamp = DateTime.UtcNow + initialVisibilityDelay;
            }
            else
            {
                newContext.MessageDelayedTime          = null;
                newContext.MessageFinalWakeUpTimeStamp = null;
            }


            await publisher.PublishEventsAsync(input, topic, newContext).ConfigureAwait(false);
        }
예제 #2
0
        private async Task InvokeStatelessHandlers <T>(T message, AFBusMessageContext messageContext, ILogger log) where T : class
        {
            //The message can not be executed in a stateless handler
            if (!messageHandlersDictionary.ContainsKey(message.GetType()))
            {
                return;
            }

            var handlerTypeList = messageHandlersDictionary[message.GetType()];

            foreach (var t in handlerTypeList)
            {
                var handler = CreateInstance(t);

                var bus = new Bus(serializer, SolveDependency <ISendMessages>(), SolveDependency <IPublishEvents>())
                {
                    Context = messageContext
                };

                object[] parametersArray = new object[] { bus, message, log };

                var methodsToInvoke = t.GetMethods().Where(m => m.GetParameters().Any(p => p.ParameterType == message.GetType()));

                foreach (var m in methodsToInvoke)
                {
                    log?.LogInformation("Invoke stateless handler " + t.ToString() + " for transaction " + messageContext.TransactionID);

                    await((Task)m.Invoke(handler, parametersArray)).ConfigureAwait(false);
                }
            }
        }
예제 #3
0
        public async Task PublishEventsAsync <T>(T message, string topicName, AFBusMessageContext messageContext) where T : class
        {
            var connectionStringBuilder = new EventHubsConnectionStringBuilder(SettingsUtil.GetSettings <string>(SETTINGS.AZURE_EVENTHUB))
            {
                EntityPath = topicName
            };

            var eventHubClient = EventHubClient.CreateFromConnectionString(connectionStringBuilder.ToString());
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(SettingsUtil.GetSettings <string>(SETTINGS.AZURE_STORAGE));

            try
            {
                var messageAsString = serializer.Serialize(message);

                var messageWithEnvelope = new AFBusMessageEnvelope()
                {
                    Context = messageContext,
                    Body    = messageAsString
                };

                messageContext.Destination = topicName;


                var finalMessage = serializer.Serialize(messageWithEnvelope);

                //if the message is bigger than the limit put the body in the blob storage
                if ((finalMessage.Length * sizeof(Char)) > MAX_MESSAGE_SIZE)
                {
                    var fileName = Guid.NewGuid().ToString("N").ToLower() + ".afbus";
                    messageWithEnvelope.Context.BodyInFile = true;

                    CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();

                    // Create a container
                    var cloudBlobContainer = cloudBlobClient.GetContainerReference(CONTAINER_NAME.ToLower());
                    await cloudBlobContainer.CreateIfNotExistsAsync().ConfigureAwait(false);

                    CloudBlockBlob blockBlob = cloudBlobContainer.GetBlockBlobReference(fileName);
                    await blockBlob.UploadTextAsync(messageWithEnvelope.Body);

                    messageWithEnvelope.Body = fileName;

                    finalMessage = serializer.Serialize(messageWithEnvelope);
                }



                await eventHubClient.SendAsync(new EventData(Encoding.UTF8.GetBytes(finalMessage)));
            }
            finally
            {
                await eventHubClient.CloseAsync();
            }
        }
예제 #4
0
        public static async Task PublishAsync <T>(T input, string topic, ISerializeMessages serializer = null, IPublishEvents publisher = null) where T : class
        {
            serializer = serializer ?? new JSONSerializer();

            var newContext = new AFBusMessageContext
            {
                MessageID     = Guid.NewGuid(),
                TransactionID = Guid.NewGuid(),
                BodyType      = typeof(T).AssemblyQualifiedName
            };

            publisher = publisher ?? new AzureEventHubPublishTransport(serializer);


            await publisher.PublishEventsAsync(input, topic, newContext).ConfigureAwait(false);
        }
예제 #5
0
        private async Task InvokeSagaHandlers <T>(T message, AFBusMessageContext messageContext, ILogger log) where T : class
        {
            //The message can not be executed in a Saga
            if (!messageToSagaDictionary.ContainsKey(message.GetType()))
            {
                return;
            }

            var instantiated = await LookForCommandsProcessedByASaga(message, messageContext, log).ConfigureAwait(false);

            instantiated = instantiated || await LookForEventsProcessedBySagas(message, messageContext, log).ConfigureAwait(false);

            if (!instantiated)
            {
                log?.LogInformation("Saga not found for message " + serializer.Serialize(message) + " for transaction " + messageContext.TransactionID);
            }
        }
예제 #6
0
        /// <summary>
        /// Sends a message to a queue named like the service.
        /// </summary>
        public static async Task SendAsync <T>(T input, string serviceName, TimeSpan?initialVisibilityDelay = null, ISerializeMessages serializer = null, ISendMessages sender = null) where T : class
        {
            serializer = serializer ?? new JSONSerializer();
            sender     = sender ?? new AzureStorageQueueSendTransport(serializer);

            var context = new AFBusMessageContext
            {
                MessageID     = Guid.NewGuid(),
                TransactionID = Guid.NewGuid(),
                BodyType      = typeof(T).AssemblyQualifiedName
            };

            if (initialVisibilityDelay != null)
            {
                context.MessageDelayedTime          = initialVisibilityDelay.Value;
                context.MessageFinalWakeUpTimeStamp = DateTime.UtcNow + initialVisibilityDelay;
            }

            await sender.SendMessageAsync(input, serviceName, context).ConfigureAwait(false);
        }
예제 #7
0
        /// <summary>
        /// Calls each function referenced by each message in the dictionary.
        /// </summary>
        public async Task HandleAsync <T>(T message, ILogger log) where T : class
        {
            if (message.GetType() == typeof(AFBusMessageEnvelope))
            {
                throw new Exception("AFBusMessageEnvelope type not permited");
            }

            if (!messageHandlersDictionary.ContainsKey(message.GetType()) && !messageToSagaDictionary.ContainsKey(message.GetType()))
            {
                throw new Exception("Handler not found for this message." + serializer.Serialize(message));
            }

            var messageContext = new AFBusMessageContext()
            {
                MessageID     = Guid.NewGuid(),
                TransactionID = Guid.NewGuid()
            };

            await InvokeStatelessHandlers(message, messageContext, log).ConfigureAwait(false);

            await InvokeSagaHandlers(message, messageContext, log).ConfigureAwait(false);
        }
예제 #8
0
        /// <summary>
        /// Calls each function referenced by each message in the dictionary.
        /// </summary>
        internal async Task HandleAsync <T>(T message, AFBusMessageContext messageContext, ILogger log) where T : class
        {
            log?.LogInformation("Message (" + messageContext.MessageID + ") of type " + message.GetType().ToString() + " received in AFBus" + " for transaction " + messageContext.TransactionID);

            if (!messageHandlersDictionary.ContainsKey(message.GetType()) && !messageToSagaDictionary.ContainsKey(message.GetType()))
            {
                throw new Exception("Handler not found for this message." + serializer.Serialize(message));
            }

            //still sometime to wait, go back to queue
            if (messageContext.MessageDelayedTime != null && messageContext.MessageDelayedTime > TimeSpan.Zero)
            {
                var transport = SolveDependency <ISendMessages>();

                var differenceUntilFinalWakeUp = messageContext.MessageFinalWakeUpTimeStamp.Value - DateTime.UtcNow;

                if (differenceUntilFinalWakeUp > TimeSpan.FromSeconds(1))
                {
                    if (differenceUntilFinalWakeUp >= transport.MaxDelay())
                    {
                        messageContext.MessageDelayedTime = transport.MaxDelay();
                    }
                    else
                    {
                        messageContext.MessageDelayedTime = differenceUntilFinalWakeUp;
                    }


                    await transport.SendMessageAsync(message, messageContext.Destination, messageContext);

                    return;
                }
            }

            await InvokeStatelessHandlers(message, messageContext, log).ConfigureAwait(false);

            await InvokeSagaHandlers(message, messageContext, log).ConfigureAwait(false);
        }
예제 #9
0
        public async Task SendMessageAsync <T>(T message, string serviceName, AFBusMessageContext messageContext) where T : class
        {
            serviceName = serviceName.ToLower();

            CloudQueue queue = queueClient.GetQueueReference(serviceName);

            if (!createdQueues.Contains(serviceName))
            {
                await queue.CreateIfNotExistsAsync();

                createdQueues.Add(serviceName);
            }


            var messageAsString = serializer.Serialize(message);

            var messageWithEnvelope = new AFBusMessageEnvelope()
            {
                Context = messageContext,
                Body    = messageAsString
            };

            messageContext.Destination = serviceName;

            TimeSpan?initialVisibilityDelay = null;

            if (messageContext.MessageDelayedTime != null && messageContext.MessageDelayedTime >= MaxDelay())
            {
                initialVisibilityDelay = MaxDelay();

                messageContext.MessageDelayedTime = MaxDelay();
            }
            else if (messageContext.MessageDelayedTime != null)
            {
                initialVisibilityDelay = messageContext.MessageDelayedTime;
            }

            if (messageContext.MessageDelayedTime != null && initialVisibilityDelay.Value < TimeSpan.Zero)
            {
                initialVisibilityDelay = null;

                messageContext.MessageDelayedTime = null;
            }

            var finalMessage = serializer.Serialize(messageWithEnvelope);

            //if the message is bigger than the limit put the body in the blob storage
            if ((finalMessage.Length * sizeof(Char)) > MAX_MESSAGE_SIZE)
            {
                var fileName = Guid.NewGuid().ToString("N").ToLower() + ".afbus";
                messageWithEnvelope.Context.BodyInFile = true;

                // Create a container
                var cloudBlobContainer = cloudBlobClient.GetContainerReference(CONTAINER_NAME.ToLower());

                CloudBlockBlob blockBlob = cloudBlobContainer.GetBlockBlobReference(fileName);
                await blockBlob.UploadTextAsync(messageWithEnvelope.Body);

                messageWithEnvelope.Body = fileName;

                finalMessage = serializer.Serialize(messageWithEnvelope);
            }

            await queue.AddMessageAsync(new CloudQueueMessage(finalMessage), null, initialVisibilityDelay, null, null).ConfigureAwait(false);
        }
예제 #10
0
        private async Task <bool> LookForEventsProcessedBySagas <T>(T message, AFBusMessageContext messageContext, ILogger log) where T : class
        {
            var instantiated = false;

            foreach (var sagaInfo in messageToSagaDictionary[message.GetType()])
            {
                var     saga        = CreateInstance(sagaInfo.SagaType);
                dynamic sagaDynamic = saga;

                var sagaMessageToMethod = sagaInfo?.EventsThatCorrelatesSagas?.FirstOrDefault(m => m.Message == message.GetType());

                //try to load saga from repository
                if (sagaMessageToMethod != null)
                {
                    var      locker = new SagaAzureStorageLocker();
                    object[] lookForInstanceParametersArray = new object[] { message };
                    sagaDynamic.SagaPersistence = new SagaAzureStoragePersistence(locker, this.lockSaga);
                    var sagasData = await((Task <List <SagaData> >)sagaMessageToMethod.CorrelatingMethod.Invoke(saga, lookForInstanceParametersArray)).ConfigureAwait(false);

                    if (sagasData != null)
                    {
                        //process each saga data independently
                        foreach (var sagaData in sagasData)
                        {
                            try
                            {
                                dynamic  finalSagaData  = sagaData;
                                SagaData lockedSagaData = await sagaDynamic.SagaPersistence.GetSagaDataAsync <SagaData>(sagaData.PartitionKey, sagaData.RowKey).ConfigureAwait(false);

                                finalSagaData.Timestamp = lockedSagaData.Timestamp;
                                finalSagaData.ETag      = lockedSagaData.ETag;
                                finalSagaData.LockID    = lockedSagaData.LockID;

                                sagaDynamic.Data = finalSagaData;

                                var bus = new Bus(serializer, SolveDependency <ISendMessages>(), SolveDependency <IPublishEvents>())
                                {
                                    Context = messageContext
                                };

                                object[] parametersArray = new object[] { bus, message, log };

                                SagaData typedSagaData = (SagaData)sagaData;
                                log?.LogInformation("Invoke event saga handler " + sagaMessageToMethod.HandlingMethod.ToString() + " for transaction " + messageContext.TransactionID);

                                await((Task)sagaMessageToMethod.HandlingMethod.Invoke(saga, parametersArray)).ConfigureAwait(false);

                                await sagaPersistence.UpdateAsync(sagaDynamic.Data).ConfigureAwait(false);

                                instantiated = true;
                            }
                            catch (Exception ex)
                            {
                                //if there is an error release the lock.
                                log?.LogError(ex.Message, ex);
                                var sagaID = sagaData.PartitionKey + sagaData.RowKey;
                                await locker.ReleaseLock(sagaID, sagaData.LockID);

                                throw;
                            }
                        }
                    }
                }
            }

            return(instantiated);
        }
예제 #11
0
        private async Task <bool> LookForCommandsProcessedByASaga <T>(T message, AFBusMessageContext messageContext, ILogger log) where T : class
        {
            var instantiated = false;

            foreach (var sagaInfo in messageToSagaDictionary[message.GetType()])
            {
                var     saga        = CreateInstance(sagaInfo.SagaType);//Activator.CreateInstance(sagaInfo.SagaType);
                dynamic sagaDynamic = saga;

                var sagaMessageToMethod = sagaInfo.CommandsThatAreCorrelatedByTheSaga.FirstOrDefault(m => m.Message == message.GetType());

                //try to load saga from repository
                if (sagaMessageToMethod != null)
                {
                    var      locker = new SagaAzureStorageLocker();
                    object[] lookForInstanceParametersArray = new object[] { message };
                    sagaDynamic.SagaPersistence = new SagaAzureStoragePersistence(locker, this.lockSaga);
                    dynamic sagaData = await((Task <SagaData>)sagaMessageToMethod.CorrelatingMethod.Invoke(saga, lookForInstanceParametersArray)).ConfigureAwait(false);

                    if (sagaData != null)
                    {
                        try
                        {
                            sagaDynamic.Data = sagaData;

                            var bus = new Bus(serializer, SolveDependency <ISendMessages>(), SolveDependency <IPublishEvents>())
                            {
                                Context = messageContext
                            };

                            object[] parametersArray = new object[] { bus, message, log };

                            SagaData typedSagaData = (SagaData)sagaData;
                            log?.LogInformation("Invoke saga handler " + sagaMessageToMethod.HandlingMethod.ToString() + " for transaction " + messageContext.TransactionID + " with key (" + typedSagaData.PartitionKey.ToString() + "," + typedSagaData.RowKey + ")");
                            await((Task)sagaMessageToMethod.HandlingMethod.Invoke(saga, parametersArray)).ConfigureAwait(false);

                            await sagaPersistence.UpdateAsync(sagaDynamic.Data).ConfigureAwait(false);

                            instantiated = true;
                        }
                        catch (Exception ex)
                        {
                            //if there is an error release the lock.
                            log?.LogError(ex.Message, ex);
                            var sagaID = sagaData.PartitionKey + sagaData.RowKey;
                            await locker.ReleaseLock(sagaID, sagaData.LockID);

                            throw;
                        }
                    }
                }


                sagaMessageToMethod = sagaInfo.CommandsThatActivateTheSaga.FirstOrDefault(m => m.Message == message.GetType());
                //if not => create the saga
                if (!instantiated && sagaMessageToMethod != null)
                {
                    var bus = new Bus(serializer, SolveDependency <ISendMessages>(), SolveDependency <IPublishEvents>())
                    {
                        Context = messageContext
                    };

                    object[] parametersArray = new object[] { bus, message, log };

                    log?.LogInformation("Invoke saga handler " + sagaMessageToMethod.HandlingMethod.ToString() + " for transaction " + messageContext.TransactionID + " creating new saga");
                    await((Task)sagaMessageToMethod.HandlingMethod.Invoke(saga, parametersArray)).ConfigureAwait(false);

                    await sagaPersistence.InsertAsync(sagaDynamic.Data).ConfigureAwait(false);

                    SagaData typedSagaData = (SagaData)sagaDynamic.Data;
                    log?.LogInformation("Saga data inserted " + sagaMessageToMethod.HandlingMethod.ToString() + " for transaction " + messageContext.TransactionID + " with key (" + typedSagaData.PartitionKey.ToString() + "," + typedSagaData.RowKey.ToString() + ")");
                    instantiated = true;
                }
            }

            return(instantiated);
        }
예제 #12
0
        public async Task PublishEventsAsync <T>(T message, string topicName, AFBusMessageContext messageContext) where T : class
        {
            var sender = new MessageSender(SettingsUtil.GetSettings <string>(SETTINGS.AZURE_SERVICEBUS), topicName.ToLower());
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(SettingsUtil.GetSettings <string>(SETTINGS.AZURE_STORAGE));


            var messageAsString = serializer.Serialize(message);

            var messageWithEnvelope = new AFBusMessageEnvelope()
            {
                Context = messageContext,
                Body    = messageAsString
            };

            messageContext.Destination = topicName;

            TimeSpan?initialVisibilityDelay = null;

            if (messageContext.MessageDelayedTime != null && messageContext.MessageDelayedTime >= MaxDelay())
            {
                initialVisibilityDelay = MaxDelay();

                messageContext.MessageDelayedTime = MaxDelay();
            }
            else if (messageContext.MessageDelayedTime != null)
            {
                initialVisibilityDelay = messageContext.MessageDelayedTime;
            }

            if (messageContext.MessageDelayedTime != null && initialVisibilityDelay.Value < TimeSpan.Zero)
            {
                initialVisibilityDelay = null;

                messageContext.MessageDelayedTime = null;
            }

            var finalMessage = serializer.Serialize(messageWithEnvelope);

            //if the message is bigger than the limit put the body in the blob storage
            if ((finalMessage.Length * sizeof(Char)) > MAX_MESSAGE_SIZE)
            {
                var fileName = Guid.NewGuid().ToString("N").ToLower() + ".afbus";
                messageWithEnvelope.Context.BodyInFile = true;

                CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();

                // Create a container
                var cloudBlobContainer = cloudBlobClient.GetContainerReference(CONTAINER_NAME.ToLower());
                await cloudBlobContainer.CreateIfNotExistsAsync().ConfigureAwait(false);

                CloudBlockBlob blockBlob = cloudBlobContainer.GetBlockBlobReference(fileName);
                await blockBlob.UploadTextAsync(messageWithEnvelope.Body);

                messageWithEnvelope.Body = fileName;

                finalMessage = serializer.Serialize(messageWithEnvelope);
            }


            var finalSBMessage = new Message(Encoding.UTF8.GetBytes(finalMessage))
            {
                ContentType = "application/json",
                Label       = topicName,
                MessageId   = messageContext.MessageID.ToString(),
                TimeToLive  = TimeSpan.FromDays(10)
            };

            if (messageContext.MessageDelayedTime.HasValue)
            {
                finalSBMessage.ScheduledEnqueueTimeUtc = DateTime.UtcNow + messageContext.MessageDelayedTime.Value;
            }


            await sender.SendAsync(finalSBMessage).ConfigureAwait(false);
        }