Example #1
0
        /// <summary>
        /// Return all saga types that are initiated by this type of message
        /// </summary>
        /// <param name="message">Initialisation message to check for</param>
        /// <param name="assemblies">Assemblies to scan for sagas</param>
        /// <returns></returns>
        internal static IEnumerable <Type> GetSagaTypesInitiatedBy(IInitiatingSagaMessage message, params Assembly[] assemblies)
        {
            try
            {
                if (assemblies.Length == 0)
                {
                    assemblies = AppDomain.CurrentDomain.GetAssemblies();
                }

                var messageType             = message.GetType();
                var initiatingInterfaceType = typeof(InitiatedBy <>).MakeGenericType(messageType);

                var scan = assemblies.SelectMany(a => a.GetTypes())
                           .Where(t => initiatingInterfaceType.IsAssignableFrom(t))
                           .ToList();

                return(scan);
            }
            catch (ReflectionTypeLoadException ex)
            {
                //Display or log the error based on your application.

                throw new Exception(BuildFusionException(ex));
            }
        }
Example #2
0
        public IAccessibleSaga ResolveSagaInititatedBy(IInitiatingSagaMessage message)
        {
            var interfaceType = typeof(InitiatedBy <>).MakeGenericType(message.GetType());
            var saga          = container.Resolve(interfaceType);

            return((IAccessibleSaga)saga);
        }
Example #3
0
        public OperationResult Consume(IInitiatingSagaMessage initiatingMessage)
        {
            if (initiatingMessage.CorrelationId == default(Guid))
            {
                throw new ArgumentException("CorrelationId was not provided in the message. Please make sure you assign CorrelationId before initiating your Saga");
            }

            // find all sagas that can be initiated by this message
            var sagaTypes = Reflection.GetSagaTypesInitiatedBy(initiatingMessage, assembliesToScan);

            if (!sagaTypes.Any())
            {
                throw new ArgumentException($"Message of type {initiatingMessage.GetType().Name} is not initiating any Sagas. Please add InitiatedBy<{initiatingMessage.GetType().Name}> to your Saga type");
            }
            if (sagaTypes.Count() > 1)
            {
                // can't have multiple sagas initiated by the same message - can't have 2 sagas of different types with the same CorrelationId
                var sagaNames = String.Join(", ", sagaTypes.Select(t => t.Name));
                throw new ArgumentException($"Message of type {initiatingMessage.GetType().Name} is initiating more than one saga. Please make sure any single message is initiating only one saga. Affected sagas: {sagaNames}");
            }

            var sagaType = sagaTypes.First();

            // try to find sagas that already exist
            var existingSaga = Reflection.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 = serviceLocator.Resolve(sagaType);

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

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

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

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

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

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

            sagaRepository.Save(saga); // now the real question - should we persist the saga if operation returned errors? Probably should be configurable

            return(errors);
        }
Example #4
0
        public OperationResult Consume(IInitiatingSagaMessage sagaMessage)
        {
            var opResult = _sagaMediator.Consume(sagaMessage);

            if (opResult.HasErrors)
            {
                Errors.AddCollection(opResult.Errors);
            }

            return(opResult);
        }
        /// <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 #6
0
        /// <summary>
        /// Return all saga types that are initiated by this type of message
        /// </summary>
        /// <param name="message">Initialisation message to check for</param>
        /// <param name="assemblies">Assemblies to scan for sagas</param>
        /// <returns></returns>
        public static IEnumerable <Type> GetSagaTypesInitiatedBy(IInitiatingSagaMessage message, params Assembly[] assemblies)
        {
            if (assemblies.Length == 0)
            {
                assemblies = AppDomain.CurrentDomain.GetAssemblies();
            }

            var messageType             = message.GetType();
            var initiatingInterfaceType = typeof(InitiatedBy <>).MakeGenericType(messageType);

            var scan = assemblies.SelectMany(a => a.GetTypes())
                       .Where(t => initiatingInterfaceType.IsAssignableFrom(t))
                       .ToList();

            return(scan);
        }
Example #7
0
 public IAccessibleSaga ResolveSagaInititatedBy(IInitiatingSagaMessage message)
 {
     throw new NotImplementedException();
 }