Example #1
0
        /// <summary>
        /// Finds and returns saga instance with the given correlation ID.
        /// You will get exceptions if TSaga does not match the actual saga data with the provided exception.
        ///
        /// Actually creates an instance of saga from service locator, retrieves SagaData and Headers from the storage and populates the instance with these.
        /// </summary>
        /// <typeparam name="TSaga">Type of saga we are looking for</typeparam>
        /// <param name="correlationId">CorrelationId to identify the saga</param>
        /// <returns>An instance of the saga. Or Null if there is no saga with this ID.</returns>
        public TSaga Find <TSaga>(Guid correlationId) where TSaga : class, IAccessibleSaga
        {
            Guard.ArgumentIsNotNull(correlationId, nameof(correlationId));

            using (var connection = connectionFactory.CreateOpenConnection())
                using (var database = new Database(connection))
                {
                    var sql           = Sql.Builder.Where("correlationId = @0", correlationId);
                    var persistedData = database.SingleOrDefault <SagaData>(sql);

                    if (persistedData == null)
                    {
                        return(null);
                    }

                    var sagaInstance = sagaFactory.ResolveSaga <TSaga>();
                    var sagaDataType = NSagaReflection.GetInterfaceGenericType <TSaga>(typeof(ISaga <>));
                    var sagaData     = messageSerialiser.Deserialise(persistedData.BlobData, sagaDataType);

                    var headersSql       = Sql.Builder.Where("correlationId = @0", correlationId);
                    var headersPersisted = database.Query <SagaHeaders>(headersSql);
                    var headers          = headersPersisted.ToDictionary(k => k.Key, v => v.Value);

                    NSagaReflection.Set(sagaInstance, "CorrelationId", correlationId);
                    NSagaReflection.Set(sagaInstance, "SagaData", sagaData);
                    NSagaReflection.Set(sagaInstance, "Headers", headers);

                    return(sagaInstance);
                }
        }
        /// <summary>
        /// Finds and returns saga instance with the given correlation ID.
        /// Actually creates an instance of saga from Saga factory, retrieves SagaData and Headers from the storage and populates the instance with these.
        /// </summary>
        /// <typeparam name="TSaga">Type of saga we are looking for</typeparam>
        /// <param name="correlationId">CorrelationId to identify the saga</param>
        /// <returns>
        /// An instance of the saga. Or Null if there is no saga with this ID.
        /// </returns>
        public TSaga Find <TSaga>(Guid correlationId) where TSaga : class, IAccessibleSaga
        {
            string dataSerialised;

            if (!DataDictionary.TryGetValue(correlationId, out dataSerialised))
            {
                return(null);
            }

            string headersSerialised;
            var    headers = new Dictionary <String, String>();

            if (HeadersDictionary.TryGetValue(correlationId, out headersSerialised))
            {
                headers = messageSerialiser.Deserialise <Dictionary <String, String> >(headersSerialised);
            }

            var sagaDataType = NSagaReflection.GetInterfaceGenericType <TSaga>(typeof(ISaga <>));

            var dataObject = messageSerialiser.Deserialise(dataSerialised, sagaDataType);

            var saga = sagaFactory.ResolveSaga <TSaga>();

            NSagaReflection.Set(saga, "SagaData", dataObject);
            NSagaReflection.Set(saga, "CorrelationId", correlationId);
            NSagaReflection.Set(saga, "Headers", headers);

            return(saga);
        }
        /// <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);
        }
Example #4
0
        /// <summary>
        /// Finds and returns saga instance with the given correlation ID.
        /// You will get exceptions if TSaga does not match the actual saga data with the provided exception.
        ///
        /// Actually creates an instance of saga from service locator, retrieves SagaData and Headers from the storage and populates the instance with these.
        /// </summary>
        /// <typeparam name="TSaga">Type of saga we are looking for</typeparam>
        /// <param name="correlationId">CorrelationId to identify the saga</param>
        /// <returns>An instance of the saga. Or Null if there is no saga with this ID.</returns>
        public TSaga Find <TSaga>(Guid correlationId) where TSaga : class, IAccessibleSaga
        {
            Guard.ArgumentIsNotNull(correlationId, nameof(correlationId));

            var persistedData = database.GetById <SagaData>(correlationId).FirstOrDefault();

            if (persistedData == null)
            {
                return(null);
            }

            var sagaInstance = sagaFactory.ResolveSaga <TSaga>();
            var sagaDataType = NSagaReflection.GetInterfaceGenericType <TSaga>(typeof(ISaga <>));
            var sagaData     = messageSerialiser.Deserialise(persistedData.BlobData, sagaDataType);

            var headersPersisted = database.GetById <SagaHeaders>(correlationId);
            var headers          = headersPersisted.ToDictionary(k => k.Key, v => v.Value);

            sagaInstance.CorrelationId = correlationId;
            sagaInstance.Headers       = headers;
            NSagaReflection.Set(sagaInstance, "SagaData", sagaData);

            return(sagaInstance);
        }