예제 #1
0
        /// <summary>
        /// Emits the given domain event, adding the aggregate root's <see cref="Id"/> and a sequence number to its metadata, along with some type information
        /// </summary>
        protected void Emit <TAggregateRoot>(DomainEvent <TAggregateRoot> e) where TAggregateRoot : AggregateRoot
        {
            if (e == null)
            {
                throw new ArgumentNullException("e", "Can't emit null!");
            }

            if (string.IsNullOrWhiteSpace(Id))
            {
                throw new InvalidOperationException(
                          string.Format(
                              "Attempted to emit event {0} from aggregate root {1}, but it has not yet been assigned an ID!",
                              e, GetType()));
            }

            var eventType = e.GetType();

            var emitterInterface = typeof(IEmit <>).MakeGenericType(eventType);

            if (!emitterInterface.IsAssignableFrom(GetType()))
            {
                throw new InvalidOperationException(
                          string.Format(
                              "Attempted to emit event {0} but the aggregate root {1} does not implement IEmit<{2}>",
                              e, GetType().Name, e.GetType().Name));
            }

            if (UnitOfWork == null)
            {
                throw new InvalidOperationException(string.Format("Attempted to emit event {0}, but the aggreate root does not have a unit of work!", e));
            }

            if (ReplayState != ReplayState.None)
            {
                throw new InvalidOperationException(string.Format("Attempted to emit event {0}, but the aggreate root's replay state is {1}! - events can only be emitted when the root is not applying events", e, ReplayState));
            }

            if (!typeof(TAggregateRoot).IsAssignableFrom(GetType()))
            {
                throw new InvalidOperationException(
                          string.Format("Attempted to emit event {0} which is owned by {1} from aggregate root of type {2}",
                                        e, typeof(TAggregateRoot), GetType()));
            }

            var now            = Time.UtcNow();
            var sequenceNumber = CurrentSequenceNumber + 1;

            e.Meta.Merge(CurrentCommandMetadata ?? new Metadata());
            e.Meta[DomainEvent.MetadataKeys.AggregateRootId] = Id;
            e.Meta[DomainEvent.MetadataKeys.TimeUtc]         = now.ToString("u");
            e.Meta[DomainEvent.MetadataKeys.SequenceNumber]  = sequenceNumber.ToString(Metadata.NumberCulture);

            e.Meta.TakeFromAttributes(eventType);
            e.Meta.TakeFromAttributes(GetType());

            try
            {
                ApplyEvent(e, ReplayState.EmitApply);
            }
            catch (Exception exception)
            {
                throw new ApplicationException(string.Format(@"Could not apply event {0} to {1} - please check the inner exception, and/or make sure that the aggregate root type is PUBLIC", e, this), exception);
            }

            UnitOfWork.AddEmittedEvent(this, e);
            EventEmitted(e);
        }