public async Task <Page> TryGetEventsAsync(long offset)
        {
            var results = new List <IEvent>();

            using (var context = _dbContextFactory.Create())
            {
                var events = await context.Events
                             .AsNoTracking()
                             .OrderBy(x => x.SequenceNo)
                             .Skip((int)offset)
                             .Take(250)
                             .ToListAsync();

                foreach (var @event in events)
                {
                    if (!_eventTypeCache.TryGet(@event.Type, out var type))
                    {
                        continue;
                    }

                    var result = (IEvent)_eventDeserializer.Deserialize(@event.Data, type);

                    results.Add(result);
                }

                return(new Page(offset + events.Count, offset, results));
            }
        }
        public IEventContext <IEvent> CreateContext(Entities.Event dbEvent)
        {
            if (dbEvent == null)
            {
                throw new ArgumentNullException(nameof(dbEvent));
            }

            if (!_eventTypeCache.TryGet(dbEvent.Type, out var type))
            {
                throw new ArgumentException($"Could not find event type for '{dbEvent.Type}'");
            }

            var @event = (IEvent)_eventDeserializer.Deserialize(dbEvent.Data, type);

            if (_cache.TryGetValue(type, out var activator))
            {
                return(activator(dbEvent.StreamId, @event, dbEvent.CorrelationId, dbEvent.CausationId, @event.Timestamp, Actor.From(dbEvent.Actor)));
            }

            activator = BuildActivator(typeof(EventContext <>).MakeGenericType(type));

            _cache.TryAdd(type, activator);

            var correlationId = dbEvent.CorrelationId != null?CorrelationId.From(dbEvent.CorrelationId) : (CorrelationId?)null;

            var causationId = dbEvent.CausationId != null?CausationId.From(dbEvent.CorrelationId) : (CausationId?)null;

            return(activator(dbEvent.StreamId, @event, correlationId, causationId, @event.Timestamp, Actor.From(dbEvent.Actor)));
        }
        public IEventContext <IEvent> CreateContext(ReceivedMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            if (!_eventTypeCache.TryGet(message.RoutingKey, out var type))
            {
                throw new ArgumentException($"Could not find event type for '{message.RoutingKey}'");
            }

            var eventData = Encoding.UTF8.GetString(message.Body);
            var @event    = (IEvent)_eventDeserializer.Deserialize(eventData, type);

            string        streamId      = null;
            CorrelationId?correlationId = null;
            CausationId?  causationId   = null;
            string        actor         = null;

            if (message.BasicProperties.Headers != null)
            {
                if (message.BasicProperties.Headers.ContainsKey(nameof(IEventContext <IEvent> .StreamId)))
                {
                    streamId = message.BasicProperties.Headers[nameof(IEventContext <IEvent> .StreamId)]?.ToString();
                }

                if (message.BasicProperties.Headers.ContainsKey(nameof(IEventContext <IEvent> .CorrelationId)))
                {
                    var value = message.BasicProperties.Headers[nameof(IEventContext <IEvent> .CorrelationId)]?.ToString();
                    correlationId = value != null?CorrelationId.From(value) : (CorrelationId?)null;
                }

                if (message.BasicProperties.Headers.ContainsKey(nameof(IEventContext <IEvent> .CausationId)))
                {
                    var value = message.BasicProperties.Headers[nameof(IEventContext <IEvent> .CausationId)]?.ToString();
                    causationId = value != null?CausationId.From(value) : (CausationId?)null;
                }

                if (message.BasicProperties.Headers.ContainsKey(nameof(IEventContext <IEvent> .Actor)))
                {
                    actor = message.BasicProperties.Headers[nameof(IEventContext <IEvent> .Actor)]?.ToString();
                }
            }

            if (_cache.TryGetValue(type, out var activator))
            {
                return(activator(streamId, @event, correlationId, causationId, @event.Timestamp, Actor.From(actor ?? "<Unknown>")));
            }

            activator = BuildActivator(typeof(EventContext <>).MakeGenericType(type));

            _cache.TryAdd(type, activator);

            return(activator(streamId, @event, correlationId, causationId, @event.Timestamp, Actor.From(actor ?? "<Unknown>")));
        }
        public async Task <Page> GetEventsAsync(long offset, CancellationToken cancellationToken = default)
        {
            var results = new List <IEventContext <IEvent> >();

            var events = await GetAllEventsForwardsInternalAsync(offset).ConfigureAwait(false);

            if (events.Count > 0 && events[0].SequenceNo != offset + 1)
            {
                _logger.LogInformation("Gap detected in stream. Expecting sequence no {ExpectedSequenceNo} but found sequence no {ActualSequenceNo}. Reloading events after {DefaultReloadInterval}ms.", offset + 1, events[0].SequenceNo, DefaultReloadInterval);
                events = await GetAllEventsAfterDelayInternalAsync(offset).ConfigureAwait(false);
            }

            for (var i = 0; i < events.Count - 1; i++)
            {
                if (events[i].SequenceNo + 1 != events[i + 1].SequenceNo)
                {
                    _logger.LogInformation("Gap detected in stream. Expecting sequence no {ExpectedSequenceNo} but found sequence no {ActualSequenceNo}. Reloading events after {DefaultReloadInterval}ms.", events[i].SequenceNo + 1, events[i + 1].SequenceNo, DefaultReloadInterval);
                    events = await GetAllEventsAfterDelayInternalAsync(offset).ConfigureAwait(false);

                    break;
                }
            }

            foreach (var @event in events)
            {
                if (!_eventTypeCache.TryGet(@event.Type, out var type))
                {
                    throw new InvalidOperationException($"Cannot find type for event '{@event.Name}' - '{@event.Type}'.");
                }

                var result = _eventContextFactory.CreateContext(@event);
                //var result = (IEvent)_eventDeserializer.Deserialize(@event.Data, type);

                results.Add(result);
            }

            return(new Page(offset + events.Count, offset, results));
        }