예제 #1
0
        static void EnsureMappingToStartMessage(SagaCorrelator correlator, Type sagaType, IEnumerable <SagaMessage> associatedMessages)
        {
            Contract.Requires(correlator != null);
            Contract.Requires(sagaType != null);
            Contract.Requires(associatedMessages != null);

            foreach (var message in associatedMessages.Where(message => message.StartsSaga))
            {
                var messageType = message.MessageType.GetTypeInfo();
                var matches     = from mapping in correlator.Mappings
                                  where mapping.MessageType.GetTypeInfo().IsAssignableFrom(messageType)
                                  select mapping;

                if (!matches.Any())
                {
                    throw new SagaConfigurationException(SR.UnmappedSagaStartMessage.FormatDefault(message.MessageType.Name, sagaType.Name));
                }
            }
        }
예제 #2
0
        static SagaToMessageMap EnsureSinglePropertyMapping(SagaCorrelator correlator, IEnumerable <SagaMessage> associatedMessages, Type sagaType)
        {
            Contract.Requires(correlator != null);
            Contract.Requires(associatedMessages != null);
            Contract.Requires(sagaType != null);
            Contract.Ensures(Contract.Result <SagaToMessageMap>() != null);

            var propertyMappings = (from message in associatedMessages
                                    where message.StartsSaga
                                    from mapping in correlator.Mappings
                                    where mapping.MessageType == message.MessageType
                                    group mapping by mapping.SagaDataProperty.Name).ToArray();

            switch (propertyMappings.Length)
            {
            case 0:
                throw new SagaConfigurationException(SR.SagaNotCorrelated);

            case 1:
                return(propertyMappings[0].First());

            default:
                var messageProperties = new StringBuilder();
                var names             = from mappings in propertyMappings
                                        from mapping in mappings
                                        select mapping.MessageProperty.Name;

                using (var name = names.Distinct().Reverse().GetEnumerator())
                {
                    name.MoveNext();
                    messageProperties.Append(SR.AndConjunction);
                    messageProperties.Append(name.Current);

                    while (name.MoveNext())
                    {
                        messageProperties.Insert(0, ", ");
                        messageProperties.Insert(0, name.Current);
                    }
                }

                throw new SagaConfigurationException(SR.TooManySagaCorrelationProperties.FormatDefault(sagaType.Name, messageProperties));
            }
        }
예제 #3
0
        static void SetSearchMethodForMappings(
            SagaCorrelator correlator,
            Type sagaType,
            Type sagaDataType,
            IEnumerable <SagaMessage> associatedMessages,
            ICollection <SagaSearchMethod> searchMethods)
        {
            Contract.Requires(correlator != null);
            Contract.Requires(sagaType != null);
            Contract.Requires(sagaDataType != null);
            Contract.Requires(associatedMessages != null);
            Contract.Requires(searchMethods != null);

            foreach (var mapping in correlator.Mappings)
            {
                var messageType       = mapping.MessageType.GetTypeInfo();
                var associatedMessage = associatedMessages.FirstOrDefault(message => messageType.IsAssignableFrom(message.MessageType.GetTypeInfo()));

                if (associatedMessage == null)
                {
                    var interfaces     = new[] { typeof(IStartWith <>), typeof(IStartWhen <>), typeof(IReceiveEvent <>), typeof(IHandleCommand <>) };
                    var interfaceNames = new StringBuilder();

                    using (var @interface = interfaces.Reverse().GetEnumerator())
                    {
                        @interface.MoveNext();
                        interfaceNames.Append(SR.OrConjunction);
                        interfaceNames.Append(@interface.Current.Name);

                        while (@interface.MoveNext())
                        {
                            interfaceNames.Insert(0, ", ");
                            interfaceNames.Insert(0, @interface.Current.Name);
                        }
                    }

                    throw new SagaConfigurationException(SR.UnhandledSagaMessage.FormatDefault(sagaType.Name, messageType.Name, interfaceNames));
                }

                SetSearchMethod(mapping, sagaDataType, searchMethods);
            }
        }
예제 #4
0
        /// <summary>
        /// Creates the metadata for a saga from the specified type.
        /// </summary>
        /// <param name="sagaType">The type of saga to create the metadata for.</param>
        /// <returns>A new <see cref="SagaMetadata"/> instance.</returns>
        /// <exception cref="ArgumentException"><paramref name="sagaType"/> is not a <see cref="ISaga{TData}"/>.</exception>
        public static SagaMetadata Create(Type sagaType)
        {
            if (!sagaType.IsSaga())
            {
                throw new ArgumentException(SR.InvalidSaga.FormatDefault(sagaType.Name));
            }

            var sagaDataType = sagaType.GetSagaDataType();
            var method       = CorrelateOfT.MakeGenericMethod(sagaDataType);
            var correlate    = (Action <Type, ICorrelateSagaToMessage>)method.CreateDelegate(typeof(Action <Type, ICorrelateSagaToMessage>));
            var correlator   = new SagaCorrelator();

            correlate(sagaType, correlator);

            var associatedMessages  = GetAssociatedMessages(sagaType).ToArray();
            var mapping             = EnsureSinglePropertyMapping(correlator, associatedMessages, sagaType);
            var correlationProperty = mapping.SagaDataProperty;
            var searchMethods       = new List <SagaSearchMethod>();

            SetSearchMethodForMappings(correlator, sagaType, sagaDataType, associatedMessages, searchMethods);
            EnsureMappingToStartMessage(correlator, sagaType, associatedMessages);

            return(new SagaMetadata(sagaType, sagaDataType, correlationProperty, associatedMessages, searchMethods));
        }
예제 #5
0
 protected override void CorrelateUsing(SagaCorrelator <TData> correlator)
 {
     Contract.Requires <ArgumentNullException>(correlator != null, nameof(correlator));
 }
예제 #6
0
 protected override void CorrelateUsing( SagaCorrelator<ProcurementData> correlator )
 {
     correlator.Correlate<SubmitPurchaseOrder>( command => command.AggregateId ).To( saga => saga.OrderId );
     correlator.Correlate<SalesOrderReceived>( @event => @event.AggregateId ).To( saga => saga.OrderId );
     correlator.Correlate<ShipmentReceived>( @event => @event.AggregateId ).To( saga => saga.OrderId );
 }