public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var objectType = value.GetType(); try { _MigratedTypes.Value[objectType] = true; var obj = JObject.FromObject(value, serializer); obj[VersionMemberName.VersionPropertyName] = VersionMemberName.GetCurrentVersion(objectType); obj.WriteTo(writer); } finally { _MigratedTypes.Value[objectType] = false; } }
/// <summary> /// Try to migrate the serialized data to a newer version using migration methods from type unserializedDataType. /// </summary> /// <param name="serializedData"></param> /// <param name="unserializedDataType"></param> /// <param name="serializer"></param> /// <returns></returns> public Tuple <TSerializedData, bool> TryMigrate(TSerializedData serializedData, Type unserializedDataType, JsonSerializer serializer) { if (serializedData == null) { throw new ArgumentNullException(nameof(serializedData)); } if (unserializedDataType == null) { throw new ArgumentNullException(nameof(unserializedDataType)); } var migrationSettings = unserializedDataType.GetTypeInfo().GetCustomAttribute <MigratableAttribute>(); if (migrationSettings == null) { return(Tuple.Create(serializedData, false)); } var version = _VersionExtractor.GetVersion(serializedData); var allMigrationMethods = VersionMemberName .GetMigrationMethods(unserializedDataType) .ToList(); var maxSupportedVersion = allMigrationMethods.LastOrDefault()?.ToVersion ?? 0; if (version > maxSupportedVersion) { throw new DataVersionTooHighException($"Trying to load data type '{unserializedDataType.FullName}' from json data " + $"at version {version}." + $" However current software only supports version {maxSupportedVersion}." + " Please update your installation with a newwer version."); } var migrationMethods = allMigrationMethods .SkipWhile(m => m.ToVersion <= version) .ToList(); var migrated = migrationMethods.Count > 0; try { serializedData = migrationMethods .Select(m => unserializedDataType.GetTypeInfo().GetDeclaredMethod(m.Name)) .Aggregate(serializedData, (data, method) => ExecuteMigration(method, data, serializer)); } catch (Exception e) { var migrationMethodVerifier = new MigrationMethodVerifier(VersionMemberName.CanAssign); var invalidMethod = migrationMethodVerifier.VerifyMigrationMethods(allMigrationMethods); foreach (var method in invalidMethod) { method.ThrowIfInvalid(e); } // Exception doesn't come from invalid migration methods -> rethrow throw; } _VersionExtractor.SetVersion(serializedData, maxSupportedVersion); return(Tuple.Create(serializedData, migrated)); }