/// <summary>
        /// Increment the sequence number of the event stream
        /// </summary>
        private async Task IncrementSequence(string writeStreamLeaseId = "")
        {
            if (null != EventStreamBlob)
            {
                bool exists = await EventStreamBlob.ExistsAsync();

                if (exists)
                {
                    await EventStreamBlob.FetchAttributesAsync();

                    int sequenceNumber;
                    if (int.TryParse(EventStreamBlob.Metadata[METADATA_SEQUENCE], out sequenceNumber))
                    {
                        sequenceNumber += 1;
                        EventStreamBlob.Metadata[METADATA_SEQUENCE] = $"{sequenceNumber }";
                        // and commit it back
                        AccessCondition condition = AccessCondition.GenerateEmptyCondition();
                        if (!string.IsNullOrWhiteSpace(writeStreamLeaseId))
                        {
                            condition.LeaseId = writeStreamLeaseId;
                        }
                        await EventStreamBlob.SetMetadataAsync(condition, null, new Microsoft.Azure.Storage.OperationContext());
                    }
                }
            }
        }
 /// <summary>
 /// Delete the blob file containing the event stream
 /// </summary>
 public void DeleteStream()
 {
     if (null != EventStreamBlob)
     {
         EventStreamBlob.Delete(Microsoft.Azure.Storage.Blob.DeleteSnapshotsOption.IncludeSnapshots);
     }
 }
示例#3
0
        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>
        /// Make sure the blob info attributes are up to date
        /// </summary>
        /// <remarks>
        /// This is similar in concept to FileSystemInfo.Refresh
        /// </remarks>
        public async Task Refresh()
        {
            if (EventStreamBlob != null)
            {
                bool exists = await EventStreamBlob.ExistsAsync();

                if (exists)
                {
                    // just refresh the attributes
                    await EventStreamBlob.FetchAttributesAsync();
                }
                else
                {
                    exists = await EventStreamBlob.Container.ExistsAsync();

                    if (!exists)
                    {
                        await EventStreamBlob.Container.CreateAsync();
                    }
                    await EventStreamBlob.CreateOrReplaceAsync();

                    // Set the original metadata
                    EventStreamBlob.Metadata[METATDATA_DOMAIN]          = DomainName;
                    EventStreamBlob.Metadata[METADATA_ENTITY_TYPE_NAME] = EntityTypeName;
                    EventStreamBlob.Metadata[METADATA_INSTANCE_KEY]     = InstanceKey;
                    EventStreamBlob.Metadata[METADATA_SEQUENCE]         = @"0";
                    EventStreamBlob.Metadata[METADATA_DATE_CREATED]     = DateTime.UtcNow.ToString("O");
                    // and commit it back
                    await EventStreamBlob.SetMetadataAsync();
                }
            }
        }
 /// <summary>
 /// Delete the blob file containing the event stream
 /// </summary>
 public async Task DeleteStream()
 {
     if (null != EventStreamBlob)
     {
         AccessCondition condition = AccessCondition.GenerateEmptyCondition();
         await EventStreamBlob.DeleteAsync(Microsoft.Azure.Storage.Blob.DeleteSnapshotsOption.IncludeSnapshots,
                                           condition,
                                           null,
                                           new Microsoft.Azure.Storage.OperationContext());
     }
 }
        /// <summary>
        /// Gets the current top sequence number of the event stream
        /// </summary>
        public async Task <int> GetSequenceNumber()
        {
            if (null != EventStreamBlob)
            {
                bool exists = await EventStreamBlob.ExistsAsync();

                if (exists)
                {
                    await EventStreamBlob.FetchAttributesAsync();

                    int sequenceNumber;
                    if (int.TryParse(EventStreamBlob.Metadata[METADATA_SEQUENCE], out sequenceNumber))
                    {
                        return(sequenceNumber);
                    }
                }
            }

            return(0);
        }
示例#7
0
        private async Task <System.IO.Stream> GetUnderlyingStream()
        {
            if (null != EventStreamBlob)
            {
                System.IO.MemoryStream targetStream = new System.IO.MemoryStream();
                try
                {
                    await EventStreamBlob.DownloadToStreamAsync(targetStream);
                }
                catch (StorageException exBlob)
                {
                    throw new EventStreamReadException(this, 0, "Unable to access the underlying event stream",
                                                       innerException: exBlob,
                                                       source: nameof(BlobEventStreamReader));
                }
                targetStream.Seek(0, System.IO.SeekOrigin.Begin);
                return(targetStream);
            }

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