public async Task <IEnumerable <IEventContext> > GetEventsWithContext(int StartingSequenceNumber = 0, DateTime?effectiveDateTime = null) { if (null != EventStreamBlob) { if (await EventStreamBlob.ExistsAsync()) { using (System.IO.Stream rawStream = await GetUnderlyingStream()) { if (!(rawStream.Position >= rawStream.Length)) { List <IEventContext> ret = new List <IEventContext>(); foreach (BlobBlockJsonWrappedEvent record in BlobBlockJsonWrappedEvent.FromBinaryStream(rawStream)) { if (null != record) { if (record.SequenceNumber >= StartingSequenceNumber) { if ((!effectiveDateTime.HasValue) || (record.WriteTime <= effectiveDateTime.Value)) { ret.Add(record); } } } } return(ret); } } } } return(Enumerable.Empty <IEventContext>()); }
/// <summary> /// Create a wrapper for this JSON event /// </summary> /// <param name="eventTypeName"> /// The type of event in this wrapper /// </param> /// <param name="sequenceNumber"> /// The ordinal sequence of the event in the event stream /// </param> /// <param name="VersionNumber"> /// The version number of the event schema /// </param> /// <param name="writeTime"> /// The date/time the event was written to the event stream /// </param> /// <param name="eventInstance"> /// Th eunderlying data for this event instance /// </param> /// <param name="context"> /// Extra context information to be written in with the event /// </param> public static BlobBlockJsonWrappedEvent Create(string eventTypeName, int sequenceNumber, int versionNumber, DateTime?writeTime, IEvent eventInstance, IWriteContext context) { if (string.IsNullOrWhiteSpace(eventTypeName)) { if (null != eventInstance) { // Use the type name if no explicit name is passed in eventTypeName = eventInstance.GetType().FullName; } else { // Mark this as being just a place holder - used when we need to copy an event stream but "wipe out" some events eventTypeName = "Placeholder event"; } } if (!writeTime.HasValue) { writeTime = DateTime.UtcNow; } BlobBlockJsonWrappedEvent ret = new BlobBlockJsonWrappedEvent() { EventTypeName = eventTypeName, SequenceNumber = sequenceNumber, VersionNumber = versionNumber }; ret.WriteTime = writeTime.Value; if (null != eventInstance) { ret.EventInstanceAsJson = JObject.FromObject(eventInstance); } if (null != context) { ret.CorrelationIdentifier = context.CorrelationIdentifier; ret.Commentary = context.Commentary; } return(ret); }
/// <summary> /// Append the event to the end of the event stream /// </summary> /// <param name="eventInstance"> /// The event to append to the end of the event stream /// </param> /// <param name="expectedTopSequenceNumber"> /// if this is set to > 0 and the event stream is further on then a consistency issue has arisen and the /// event should not be written but rather throw an error /// </param> /// <param name="eventVersionNumber"> /// The version number to add to the event wrapper /// </param> /// <param name="streamConstraint"> /// An additional constrain that must be satisfied by the event stream in order to persist the event /// </param> /// <returns></returns> public async Task <IAppendResult> AppendEvent(IEvent eventInstance, int expectedTopSequenceNumber = 0, int eventVersionNumber = 1, EventStreamExistenceConstraint streamConstraint = EventStreamExistenceConstraint.Loose) { if (base.EventStreamBlob != null) { // acquire a lease for the blob.. string writeStreamLeaseId = null; if (await Exists()) { writeStreamLeaseId = await base.EventStreamBlob.AcquireLeaseAsync(TimeSpan.FromSeconds(15)); } int nextSequence = await base.GetSequenceNumber() + 1; if (expectedTopSequenceNumber > 0) { // check against actual top sequence number if ((expectedTopSequenceNumber + 1) < nextSequence) { throw new EventStreamWriteException(this, (nextSequence - 1), message: $"Out of sequence write - expected seqeunce number {expectedTopSequenceNumber }", source: "Blob Event Stream Writer"); } } string eventName = ""; if (null != eventInstance) { eventName = EventNameAttribute.GetEventName(eventInstance.GetType()); } // create an access condition AccessCondition condition = AccessCondition.GenerateEmptyCondition(); if (streamConstraint == EventStreamExistenceConstraint.MustBeNew) { condition = AccessCondition.GenerateIfNotExistsCondition(); } if (streamConstraint == EventStreamExistenceConstraint.MustExist) { condition = AccessCondition.GenerateIfExistsCondition(); } if (!string.IsNullOrWhiteSpace(writeStreamLeaseId)) { condition.LeaseId = writeStreamLeaseId; } // default the writer context if it is not already set if (null == _writerContext) { _writerContext = WriteContext.DefaultWriterContext(); } BlobBlockJsonWrappedEvent evtToWrite = BlobBlockJsonWrappedEvent.Create(eventName, nextSequence, eventVersionNumber, null, eventInstance, _writerContext); try { // Create it if it doesn't exist and initialsie the metadata await base.Refresh(); Microsoft.Azure.Storage.OperationContext context = new Microsoft.Azure.Storage.OperationContext() { }; await EventStreamBlob.AppendBlockAsync(new System.IO.MemoryStream(Encoding.UTF8.GetBytes(evtToWrite.ToJSonText())), "", condition, null, // use the default blob request options context ); } catch (Microsoft.Azure.Storage.StorageException exBlob) { throw new EventStreamWriteException(this, (nextSequence - 1), message: "Failed to save an event to the event stream", source: "Blob Event Stream Writer", innerException: exBlob); } await IncrementSequence(writeStreamLeaseId); if (!string.IsNullOrWhiteSpace(writeStreamLeaseId)) { // and release the lease await base.EventStreamBlob.ReleaseLeaseAsync(condition); } int sequence = await base.GetSequenceNumber(); return(new AppendResult((sequence == 0), sequence)); } else { return(null); } }