/// <summary>
 /// Initializes a new instance of the <see cref="PipelineContext"/> class.
 /// </summary>
 /// <param name="message">The message.</param>
 /// <param name="saga">The saga.</param>
 /// <param name="operationResult">The operation result. Null of operation have not finished</param>
 public PipelineContext(ISagaMessage message, IAccessibleSaga saga, OperationResult operationResult = null)
 {
     this.Message        = message;
     this.AccessibleSaga = saga;
     SagaData            = NSagaReflection.Get(saga, "SagaData");
     OperationResult     = operationResult;
 }
Example #2
0
        /// <summary>
        /// Deletes the saga instance from the storage
        /// </summary>
        /// <typeparam name="TSaga">Type of saga</typeparam>
        /// <param name="saga">Saga to be deleted</param>
        public void Complete <TSaga>(TSaga saga) where TSaga : class, IAccessibleSaga
        {
            Guard.ArgumentIsNotNull(saga, nameof(saga));

            var correlationId = (Guid)NSagaReflection.Get(saga, "CorrelationId");

            Complete(correlationId);
        }
Example #3
0
        /// <summary>
        /// Persists the instance of saga into the database storage.
        ///
        /// Actually stores SagaData and Headers. All other variables in saga are not persisted
        /// </summary>
        /// <typeparam name="TSaga">Type of saga</typeparam>
        /// <param name="saga">Saga instance</param>
        public void Save <TSaga>(TSaga saga) where TSaga : class, IAccessibleSaga
        {
            Guard.ArgumentIsNotNull(saga, nameof(saga));

            var sagaData      = NSagaReflection.Get(saga, "SagaData");
            var sagaHeaders   = (Dictionary <String, String>)NSagaReflection.Get(saga, "Headers");
            var correlationId = (Guid)NSagaReflection.Get(saga, "CorrelationId");

            var serialisedData = messageSerialiser.Serialise(sagaData);

            var dataModel = new SagaData()
            {
                CorrelationId = correlationId,
                BlobData      = serialisedData,
            };

            using (var connection = connectionFactory.CreateOpenConnection())
                using (var database = new Database(connection))
                    using (var transaction = database.GetTransaction())
                    {
                        try
                        {
                            int updatedRaws = database.Update(dataModel);

                            if (updatedRaws == 0)
                            {
                                // no records were updated - this means no records already exist - need to insert new record
                                database.Insert(dataModel);
                            }

                            // delete all existing headers
                            database.Delete <SagaHeaders>("WHERE CorrelationId=@0", correlationId);

                            // and insert updated ones
                            foreach (var header in sagaHeaders)
                            {
                                var storedHeader = new SagaHeaders()
                                {
                                    CorrelationId = correlationId,
                                    Key           = header.Key,
                                    Value         = header.Value,
                                };

                                database.Insert(storedHeader);
                            }
                            transaction.Complete();
                        }
                        catch (Exception)
                        {
                            transaction.Dispose();
                            throw;
                        }
                    }
        }
        /// <summary>
        /// Persists the instance of saga into the database storage.
        /// Actually stores SagaData and Headers. All other variables in saga are not persisted
        /// </summary>
        /// <typeparam name="TSaga">Type of saga</typeparam>
        /// <param name="saga">Saga instance</param>
        public void Save <TSaga>(TSaga saga) where TSaga : class, IAccessibleSaga
        {
            var sagaData      = NSagaReflection.Get(saga, "SagaData");
            var correlationId = (Guid)NSagaReflection.Get(saga, "CorrelationId");
            var headers       = (Dictionary <String, String>)NSagaReflection.Get(saga, "Headers");

            var serialisedData    = messageSerialiser.Serialise(sagaData);
            var serialisedHeaders = messageSerialiser.Serialise(headers);

            DataDictionary[correlationId]    = serialisedData;
            HeadersDictionary[correlationId] = serialisedHeaders;
        }
Example #5
0
        /// <summary>
        /// Persists the instance of saga into the database storage.
        ///
        /// Actually stores SagaData and Headers. All other variables in saga are not persisted
        /// </summary>
        /// <typeparam name="TSaga">Type of saga</typeparam>
        /// <param name="saga">Saga instance</param>
        public void Save <TSaga>(TSaga saga) where TSaga : class, IAccessibleSaga
        {
            Guard.ArgumentIsNotNull(saga, nameof(saga));

            var sagaData      = NSagaReflection.Get(saga, "SagaData");
            var sagaHeaders   = saga.Headers;
            var correlationId = saga.CorrelationId;

            var serialisedData = messageSerialiser.Serialise(sagaData);

            var dataModel = new SagaData()
            {
                CorrelationId = correlationId,
                BlobData      = serialisedData,
            };

            using (var transaction = database.BeginTransaction())
            {
                try
                {
                    int updatedRaws = database.Update(dataModel);

                    if (updatedRaws == 0)
                    {
                        // no records were updated - this means no records already exist - need to insert new record
                        database.Insert(dataModel);
                    }

                    // delete all existing headers
                    database.DeleteById <SagaHeaders>(correlationId);

                    // and insert updated ones
                    foreach (var header in sagaHeaders)
                    {
                        var storedHeader = new SagaHeaders()
                        {
                            CorrelationId = correlationId,
                            Key           = header.Key,
                            Value         = header.Value,
                        };

                        database.Insert(storedHeader);
                    }
                    transaction.CommitTransaction();
                }
                catch (Exception ex)
                {
                    transaction.RollbackTransaction();
                    throw;
                }
            }
        }
        /// <summary>
        /// Consumes the specified initiating message and creates a new instance of the correlating saga.
        /// <para>Saga is not persisted if operation have failed</para>
        /// </summary>
        /// <param name="initiatingMessage">The initiating message.</param>
        /// <returns>
        /// Result of the operation
        /// </returns>
        /// <exception cref="System.ArgumentException"></exception>
        public OperationResult Consume(IInitiatingSagaMessage initiatingMessage)
        {
            Guard.CheckSagaMessage(initiatingMessage, nameof(initiatingMessage));

            var resolvedSaga = sagaFactory.ResolveSagaInititatedBy(initiatingMessage);
            var sagaType     = resolvedSaga.GetType();

            // try to find sagas that already exist
            var existingSaga = NSagaReflection.InvokeGenericMethod(sagaRepository, "Find", sagaType, initiatingMessage.CorrelationId);

            if (existingSaga != null)
            {
                throw new ArgumentException($"Trying to initiate the same saga twice. {initiatingMessage.GetType().Name} is Initiating Message, but saga of type {sagaType.Name} with CorrelationId {initiatingMessage.CorrelationId} already exists");
            }

            // now create an instance of saga and persist the data
            var saga = sagaFactory.ResolveSaga(sagaType);

            NSagaReflection.Set(saga, "CorrelationId", initiatingMessage.CorrelationId);

            // if SagaData is null - create an instance of the object and assign to saga
            var sagaData = NSagaReflection.Get(saga, "SagaData");

            if (sagaData == null)
            {
                var sagaDataType = NSagaReflection.GetInterfaceGenericType(saga, typeof(ISaga <>));
                var newSagaData  = Activator.CreateInstance(sagaDataType);
                NSagaReflection.Set(saga, "SagaData", newSagaData);
            }

            var sagaHeaders = NSagaReflection.Get(saga, "Headers");

            if (sagaHeaders == null)
            {
                NSagaReflection.Set(saga, "Headers", new Dictionary <String, String>());
            }

            pipelineHook.BeforeInitialisation(new PipelineContext(initiatingMessage, (IAccessibleSaga)saga));

            var errors = (OperationResult)NSagaReflection.InvokeMethod(saga, "Initiate", initiatingMessage);

            pipelineHook.AfterInitialisation(new PipelineContext(initiatingMessage, (IAccessibleSaga)saga, errors));

            if (errors.IsSuccessful)
            {
                sagaRepository.Save(saga);
                pipelineHook.AfterSave(new PipelineContext(initiatingMessage, (IAccessibleSaga)saga, errors));
            }

            return(errors);
        }
        /// <summary>
        /// Deletes the saga instance from the storage
        /// </summary>
        /// <typeparam name="TSaga">Type of saga</typeparam>
        /// <param name="saga">Saga to be deleted</param>
        public void Complete <TSaga>(TSaga saga) where TSaga : class, IAccessibleSaga
        {
            var correlationId = (Guid)NSagaReflection.Get(saga, "CorrelationId");

            Complete(correlationId);
        }