/// <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); }