/// <summary> /// Compares the current snapshot with the expected snapshot and applies /// the compare rules of the compare actions. /// </summary> /// <param name="matchOptions">The compare actions, which will be used for special comparion.</param> /// <param name="expectedSnapshot">The original snapshot of the current result.</param> /// <param name="actualSnapshot">The actual (modifiable) snapshot of the current result.</param> public void CompareSnapshots( string expectedSnapshot, string actualSnapshot, Func <MatchOptions, MatchOptions> matchOptions) { JToken originalActualSnapshotToken = _snapshotSerializer.Deserialize(actualSnapshot); JToken actualSnapshotToken = _snapshotSerializer.Deserialize(actualSnapshot); JToken expectedSnapshotToken = _snapshotSerializer.Deserialize(expectedSnapshot); if (matchOptions != null) { ExecuteFieldMatchActions( originalActualSnapshotToken, actualSnapshotToken, expectedSnapshotToken, matchOptions); } string actualSnapshotToCompare = _snapshotSerializer .SerializeJsonToken(actualSnapshotToken); string expectedSnapshotToCompare = _snapshotSerializer .SerializeJsonToken(expectedSnapshotToken); _snapshotAssert.Assert(expectedSnapshotToCompare, actualSnapshotToCompare); }
private Snapshot Deserialize(Models.Snapshot dto) { // Todo: Type cache? var snapshot = _snapshotSerializer.Deserialize(dto.Content, Type.GetType(dto.Type)); snapshot.AggregateId = dto.AggregateId; snapshot.Version = dto.Version; return(snapshot); }
// version has 2 bytes //private const int _versionLen = 2; // buffer length 4 bytes //private const int _bufSizeLen = 4; public SnapshotStorageDate(string fileName, ISnapshotSerializer <TKey, TMessage> serializer) { if (fileName.IsEmpty()) { throw new ArgumentNullException(nameof(fileName)); } _fileName = fileName; _serializer = serializer ?? throw new ArgumentNullException(nameof(serializer)); if (File.Exists(_fileName)) { Debug.WriteLine($"Snapshot (Load): {_fileName}"); using (var stream = File.OpenRead(_fileName)) { _version = new Version(stream.ReadByte(), stream.ReadByte()); while (stream.Position < stream.Length) { var size = stream.Read <int>(); var buffer = new byte[size]; stream.ReadBytes(buffer, buffer.Length); //var offset = stream.Position; TMessage message; try { message = _serializer.Deserialize(_version, buffer); } catch (Exception ex) { ex.LogError(); continue; } var key = _serializer.GetKey(message); _snapshots.Add(key, message); _buffers.Add(key, buffer); } //_currOffset = stream.Length; } } else { _version = _serializer.Version; //_currOffset = _versionLen; } }
/// <summary> /// 从给定的快照数据对象萃取得到快照对象。 /// </summary> /// <param name="serializer"></param> /// <param name="dataObject">快照数据对象</param> /// <returns>快照对象</returns> public static ISnapshot <TAggregateRootId> ExtractSnapshot <TAggregateRootId>(this ISnapshotSerializer serializer, SnapshotDataObject <TAggregateRootId> dataObject) { var snapshotType = Type.GetType(dataObject.SnapshotType); if (snapshotType == null) { return(null); } return((ISnapshot <TAggregateRootId>)serializer.Deserialize(snapshotType, dataObject.SnapshotData)); }
/// <summary> /// Extracts the snapshot from the current snapshot data object. /// </summary> /// <returns>The snapshot instance.</returns> public ISnapshot ExtractSnapshot() { try { Type snapshotType = Type.GetType(SnapshotType); if (snapshotType == null) { return(null); } return((ISnapshot)serializer.Deserialize(snapshotType, this.SnapshotData)); } catch { throw; } }
void ISnapshotStorage.Init() { if (!Directory.Exists(_path)) { Directory.CreateDirectory(_path); } var fileName = Path.Combine(_path, _serializer.FileName); byte[] buffer; Version version; if (File.Exists(fileName)) { using (var stream = File.OpenRead(fileName)) { version = new Version(stream.ReadByte(), stream.ReadByte()); buffer = new byte[_serializer.GetSnapshotSize(version)]; while (stream.Position < stream.Length) { stream.ReadBytes(buffer, buffer.Length); var message = _serializer.Deserialize(version, buffer); _snapshots.Add(_serializer.GetSecurityId(message), Tuple.Create(stream.Position - buffer.Length, message)); } _maxOffset = stream.Position; } } else { version = _serializer.Version; _maxOffset = 2; // version bytes buffer = new byte[_serializer.GetSnapshotSize(version)]; } _snapshotSize = buffer.Length; var isFlushing = false; ThreadingHelper.Timer(() => { Tuple <long, TMessage>[] changed; lock (_snapshots.SyncRoot) { if (_dirtySecurities.Count == 0) { return; } if (isFlushing) { return; } isFlushing = true; changed = _dirtySecurities.Select(id => { var tuple = _snapshots[id]; return(Tuple.Create(tuple.Item1, (TMessage)tuple.Item2.Clone())); }).OrderBy(t => t.Item1).ToArray(); _dirtySecurities.Count = 0; } try { using (var stream = File.OpenWrite(fileName)) { if (stream.Length == 0) { stream.WriteByte((byte)version.Major); stream.WriteByte((byte)version.Minor); } foreach (var tuple in changed) { stream.Seek(tuple.Item1, SeekOrigin.Begin); Array.Clear(buffer, 0, buffer.Length); _serializer.Serialize(version, tuple.Item2, buffer); stream.Write(buffer, 0, buffer.Length); } } } catch (Exception ex) { ex.LogError(); } lock (_snapshots.SyncRoot) isFlushing = false; }).Interval(TimeSpan.FromSeconds(10)); }
/// <summary> /// Retrieves an aggregate, load your historical events and add to tracking. /// </summary> /// <typeparam name="TAggregate"></typeparam> /// <param name="id"></param> /// <returns></returns> /// <exception cref="AggregateNotFoundException"></exception> public async Task <TAggregate> GetByIdAsync <TAggregate>(Guid id) where TAggregate : Aggregate, new() { _logger.LogDebug($"Getting aggregate '{typeof(TAggregate).FullName}' with identifier: '{id}'."); var aggregate = _aggregateTracker.GetById <TAggregate>(id); _logger.LogDebug("Returning an aggregate tracked."); if (aggregate != null) { RegisterForTracking(aggregate); return(aggregate); } aggregate = new TAggregate(); IEnumerable <ICommitedEvent> events; _logger.LogDebug("Checking if aggregate has snapshot support."); if (_snapshotStrategy.CheckSnapshotSupport(aggregate.GetType())) { var snapshotAggregate = aggregate as ISnapshotAggregate; if (snapshotAggregate != null) { int version = 0; var snapshot = await _eventStore.GetLatestSnapshotByIdAsync(id).ConfigureAwait(false); if (snapshot != null) { version = snapshot.AggregateVersion; _logger.LogDebug("Restoring snapshot."); var snapshotRestore = _snapshotSerializer.Deserialize(snapshot); snapshotAggregate.Restore(snapshotRestore); _logger.LogDebug("Snapshot restored."); } events = await _eventStore.GetEventsForwardAsync(id, version).ConfigureAwait(false); LoadAggregate(aggregate, events); } } else { events = await _eventStore.GetAllEventsAsync(id).ConfigureAwait(false); LoadAggregate(aggregate, events); } if (aggregate.Id.Equals(Guid.Empty)) { _logger.LogError($"The aggregate ({typeof(TAggregate).FullName} {id}) was not found."); throw new AggregateNotFoundException(typeof(TAggregate).Name, id); } RegisterForTracking(aggregate); return(aggregate); }