Пример #1
0
        /// <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
        {
            var sagasTable = GetSagaTable();

            var retrieveOperation = TableOperation.Retrieve <StorageModel>(PartitionKey, correlationId.ToString());

            var retrieveResult = sagasTable.Execute(retrieveOperation);

            if (retrieveResult.Result == null)
            {
                return(null);
            }

            var storedModel  = (StorageModel)retrieveResult.Result;
            var sagaDataType = NSagaReflection.GetInterfaceGenericType <TSaga>(typeof(ISaga <>));
            var sagaData     = messageSerialiser.Deserialise(storedModel.BlobData, sagaDataType);

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

            sagaInstance.CorrelationId = correlationId;
            sagaInstance.Headers       = messageSerialiser.Deserialise <Dictionary <String, String> >(storedModel.Headers);
            NSagaReflection.Set(sagaInstance, "SagaData", sagaData);

            return(sagaInstance);
        }
Пример #2
0
        /// <summary>
        /// Extension method to execute default NSaga components registration in Autofac Container Builder.
        /// <para>
        /// Default registrations are:
        /// <list type="bullet">
        /// <item><description><see cref="JsonNetSerialiser"/> to serialise messages; </description></item>
        /// <item><description><see cref="InMemorySagaRepository"/> to store saga datas; </description></item>
        /// <item><description><see cref="AutofacSagaFactory"/> to resolve instances of Sagas;</description></item>
        /// <item><description><see cref="SagaMetadata"/> to work as the key component - SagaMediator;</description></item>
        /// <item><description><see cref="MetadataPipelineHook"/> added to the pipeline to preserve metadata about incoming messages.</description></item>
        /// </list>
        /// </para>
        /// </summary>
        /// <param name="builder">Container Builder to do the registration</param>
        /// <param name="assemblies">Assemblies to scan for Sagas</param>
        /// <returns>The same container builder so the calls can be chained in Builder-fashion</returns>
        public static ContainerBuilder RegisterNSagaComponents(this ContainerBuilder builder, params Assembly[] assemblies)
        {
            Guard.ArgumentIsNotNull(builder, nameof(builder));
            Guard.ArgumentIsNotNull(assemblies, nameof(assemblies));

            builder.RegisterType <AutofacSagaFactory>().As <ISagaFactory>();
            builder.RegisterType <JsonNetSerialiser>().As <IMessageSerialiser>();
            builder.RegisterType <InMemorySagaRepository>().As <ISagaRepository>();
            builder.RegisterType <SagaMediator>().As <ISagaMediator>();
            builder.RegisterType <MetadataPipelineHook>().As <IPipelineHook>();


            var sagatTypesDefinitions = NSagaReflection.GetAllSagasInterfaces(assemblies);

            foreach (var sagatTypesDefinition in sagatTypesDefinitions)
            {
                builder.RegisterType(sagatTypesDefinition.Key).As(sagatTypesDefinition.Value);
            }

            var allSagaTypes = NSagaReflection.GetAllSagaTypes(assemblies);

            builder.RegisterTypes(allSagaTypes.ToArray());

            return(builder);
        }
Пример #3
0
        public void GetSagaTypes_Always_ContainsMySaga()
        {
            // Act
            var result = NSagaReflection.GetAllSagaTypes(new Assembly[] { typeof(NSagaReflectionTests).Assembly });

            // Assert
            result.Should().Contain(s => s == typeof(MySaga))
            .And.Contain(s => s == typeof(SagaWithErrors))
            .And.HaveCount(2);
        }
Пример #4
0
        public void GetSagaTypesConsuming_Returns_MySaga()
        {
            //Arrange
            var consumedMessage = new MySagaConsumingMessage();

            // Act
            var result = NSagaReflection.GetSagaTypesConsuming(consumedMessage, typeof(NSagaReflectionTests).Assembly);

            // Assert
            result.Should().HaveCount(1).And.Contain(typeof(MySaga));
        }
Пример #5
0
        public void GetSagaTypesInitiatedBy_Returns_MySaga()
        {
            // Arrange
            var initiatingMessage = new MySagaInitiatingMessage();

            // Act
            var result = NSagaReflection.GetSagaTypesInitiatedBy(initiatingMessage, typeof(NSagaReflectionTests).Assembly);

            // Assert
            result.Should().HaveCount(1).And.Contain(typeof(MySaga));
        }
Пример #6
0
        public void InvokeMethod_OverloadInt_CallsTheCorrectOverload()
        {
            //Arrange
            var testSubject = new MyReflectionTestSubject();
            var expectedInt = 42;

            // Act
            NSagaReflection.InvokeMethod(testSubject, "Overload", expectedInt);

            // Assert
            testSubject.OverloadInt.Should().Be(expectedInt);
        }
Пример #7
0
        public void InvokeMethod_OverloadString_CallsTheCorrectOverload()
        {
            //Arrange
            var testSubject    = new MyReflectionTestSubject();
            var expectedString = Guid.NewGuid().ToString();

            // Act
            NSagaReflection.InvokeMethod(testSubject, "Overload", expectedString);

            // Assert
            testSubject.OverloadString.Should().Be(expectedString);
        }
Пример #8
0
        public void InvokeMethod_Does_NotThrow()
        {
            //Arrange
            var testSubject = new MyReflectionTestSubject();
            var expected    = Guid.NewGuid();

            // Act
            NSagaReflection.InvokeMethod(testSubject, "Initialise", expected);

            // Assert
            testSubject.Id.Should().Be(expected);
        }
Пример #9
0
        public void InvokeGenericMethod_Does_NotThrow()
        {
            // Arrange
            var sagaType = NSagaReflection.GetSagaTypesInitiatedBy(new MySagaInitiatingMessage()).First(); // there could be only one!

            var spy          = new RepositorySpy();
            var repository   = new MyStubRepository(spy);
            var expectedGuid = Guid.NewGuid();

            // Act
            NSagaReflection.InvokeGenericMethod(repository, "Find", sagaType, expectedGuid);

            // Assert
            spy.Find.Should().Be(expectedGuid);
        }
Пример #10
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
        {
            var sagasTable = GetSagaTable();

            var sagaData       = NSagaReflection.Get(saga, "SagaData");
            var serialisedData = messageSerialiser.Serialise(sagaData);

            var storageModel = new StorageModel()
            {
                RowKey   = saga.CorrelationId.ToString(),
                Headers  = messageSerialiser.Serialise(saga.Headers),
                BlobData = serialisedData,
            };

            var insertOperation = TableOperation.InsertOrReplace(storageModel);

            sagasTable.Execute(insertOperation);
        }
Пример #11
0
        /// <summary>
        /// Extension method to execute default NSaga components registration in StructureMap Container Builder.
        /// <para>
        /// Default registrations are:
        /// <list type="bullet">
        /// <item><description><see cref="JsonNetSerialiser"/> to serialise messages; </description></item>
        /// <item><description><see cref="InMemorySagaRepository"/> to store saga datas; </description></item>
        /// <item><description><see cref="StructureMapSagaFactory"/> to resolve instances of Sagas;</description></item>
        /// <item><description><see cref="SagaMetadata"/> to work as the key component - SagaMediator;</description></item>
        /// <item><description><see cref="MetadataPipelineHook"/> added to the pipeline to preserve metadata about incoming messages.</description></item>
        /// </list>
        /// </para>
        /// </summary>
        /// <param name="builder">Container Builder to do the registration</param>
        /// <param name="assemblies">Assemblies to scan for Sagas</param>
        /// <returns>The same container builder so the calls can be chained in Builder-fashion</returns>
        public static Container RegisterNSagaComponents(this Container builder, params Assembly[] assemblies)
        {
            Guard.ArgumentIsNotNull(builder, nameof(builder));
            Guard.ArgumentIsNotNull(assemblies, nameof(assemblies));

            builder.Configure(x => {
                x.AddRegistry <NSagaRegistry>();

                var sagatTypesDefinitions = NSagaReflection.GetAllSagasInterfaces(assemblies);
                foreach (var sagatTypesDefinition in sagatTypesDefinitions)
                {
                    x.AddType(sagatTypesDefinition.Value, sagatTypesDefinition.Key.UnderlyingSystemType);
                }

                var allSagaTypes = NSagaReflection.GetAllSagaTypes(assemblies).ToList();
                allSagaTypes.ToList().ForEach(t => { x.For(t); });
            });

            return(builder);
        }