public async Task <TEventSourcedAggregate?> GetAsync(TId id, CancellationToken token = default)
        {
            var streamName       = GetStreamName(id);
            var readStreamResult = _client.ReadStreamAsync(Direction.Forwards, streamName, StreamPosition.Start, cancellationToken: token);

            if (await readStreamResult.ReadState is ReadState.StreamNotFound)
            {
                return(null);
            }

            TEventSourcedAggregate?aggregate = null;

            await foreach (var resolvedEvent in readStreamResult)
            {
                var(@event, metadata) = EventStoreSerializer.Deserialize(resolvedEvent.Event);

                if (RequestContext.RequestId is not null && RequestContext.RequestId == metadata.CausationId)
                {
                    throw new DuplicateRequestException(RequestContext.RequestId);
                }

                aggregate ??= (TEventSourcedAggregate)Activator.CreateInstance(typeof(TEventSourcedAggregate), true) !;
                aggregate.ApplyEvent(@event);
            }

            return(aggregate);
        }
        public async Task SaveAsync(TEventSourcedAggregate aggregate, CancellationToken token = default)
        {
            if (!aggregate.UncommittedEvents.Any())
            {
                return;
            }

            var streamName = GetStreamName(aggregate.Id);

            var originalAggregateVersion = aggregate.Version - aggregate.UncommittedEvents.Count;
            var expectedStreamRevision   = originalAggregateVersion is 0
                ? StreamRevision.None
                : new StreamRevision((ulong)originalAggregateVersion - 1);

            var metadata = new EventMetadata(
                CausationId: RequestContext.RequestId,
                CorrelationId: RequestContext.CorrelationId);

            var eventsToSave = aggregate.UncommittedEvents.Select(@event => EventStoreSerializer.Serialize(@event, metadata));

            try
            {
                await _client.AppendToStreamAsync(streamName, expectedStreamRevision, eventsToSave, cancellationToken : token);
            }
            catch (WrongExpectedVersionException e)
                when(e.ExpectedStreamRevision == StreamRevision.None)
                {
                    throw new Exceptions.DuplicateKeyException(aggregate.Id);
                }

            aggregate.MarkEventsAsCommitted();
        }