diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs
index 366906f66e..bc5f4bef28 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs
@@ -27,6 +27,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Json
options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory());
options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter());
+
+ options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter());
+ options.JsonSerializerOptions.Converters.Add(new AbpExtraPropertyDictionaryJsonConverterFactory());
}
}
}
diff --git a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj
index 1ef71853fa..ef88ab752b 100644
--- a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj
+++ b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj
@@ -16,6 +16,7 @@
+
diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs
index 626e084ca6..a5d6d111b1 100644
--- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs
+++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Json.SystemTextJson.JsonConverters;
@@ -21,6 +21,9 @@ namespace Volo.Abp.Json.SystemTextJson
options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory());
options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter());
+
+ options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter());
+ options.JsonSerializerOptions.Converters.Add(new AbpExtraPropertyDictionaryJsonConverterFactory());
}
}
}
diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpExtraPropertyDictionaryJsonConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpExtraPropertyDictionaryJsonConverter.cs
new file mode 100644
index 0000000000..5a4ef9d2df
--- /dev/null
+++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpExtraPropertyDictionaryJsonConverter.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Volo.Abp.Data;
+using Volo.Abp.ObjectExtending;
+
+namespace Volo.Abp.Json.SystemTextJson.JsonConverters
+{
+ public class AbpExtraPropertyDictionaryJsonConverter : JsonConverter
+ where T : ExtensibleObject
+ {
+ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ var newOptions = new JsonSerializerOptions(options);
+ newOptions.Converters.RemoveAll(x => x == this || x.GetType() == typeof(AbpExtraPropertyDictionaryJsonConverterFactory));
+
+ var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
+ var extensibleObject = JsonSerializer.Deserialize(rootElement.GetRawText(), newOptions);
+ var extraProperties = rootElement.EnumerateObject().FirstOrDefault(x =>
+ x.Name.Equals(nameof(ExtensibleObject.ExtraProperties), StringComparison.OrdinalIgnoreCase))
+ .Value.GetRawText();
+
+ var extraPropertyDictionary = JsonSerializer.Deserialize(extraProperties, typeof(ExtraPropertyDictionary), newOptions);
+
+ ObjectHelper.TrySetProperty(extensibleObject, x => x.ExtraProperties, () => extraPropertyDictionary);
+
+ return extensibleObject;
+ }
+
+ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
+ {
+ var newOptions = new JsonSerializerOptions(options);
+ newOptions.Converters.RemoveAll(x => x == this || x.GetType() == typeof(AbpExtraPropertyDictionaryJsonConverterFactory));
+ JsonSerializer.Serialize(writer, value, newOptions);
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpExtraPropertyDictionaryJsonConverterFactory.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpExtraPropertyDictionaryJsonConverterFactory.cs
new file mode 100644
index 0000000000..9dabd86b85
--- /dev/null
+++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpExtraPropertyDictionaryJsonConverterFactory.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Reflection;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Volo.Abp.ObjectExtending;
+
+namespace Volo.Abp.Json.SystemTextJson.JsonConverters
+{
+ public class AbpExtraPropertyDictionaryJsonConverterFactory : JsonConverterFactory
+ {
+ public override bool CanConvert(Type typeToConvert)
+ {
+ return typeToConvert == typeof(ExtensibleObject) || typeToConvert.IsSubclassOf(typeof(ExtensibleObject));
+ }
+
+ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
+ {
+ return (JsonConverter) Activator.CreateInstance(
+ typeof(AbpExtraPropertyDictionaryJsonConverter<>).MakeGenericType(typeToConvert),
+ BindingFlags.Instance | BindingFlags.Public,
+ binder: null,
+ null,
+ culture: null)!;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs
index 02fa9bbaff..c323293dd9 100644
--- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs
+++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs
@@ -51,7 +51,9 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
public override void Write(Utf8JsonWriter writer, object objectToWrite, JsonSerializerOptions options)
{
- throw new InvalidOperationException("Should not get here.");
+ var newOptions = new JsonSerializerOptions(options);
+ newOptions.Converters.Remove(this);
+ JsonSerializer.Serialize(writer, objectToWrite, newOptions);
}
}
}
diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs
index dd4a366b03..da49f7ebc6 100644
--- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs
+++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs
@@ -1,5 +1,7 @@
using Shouldly;
+using Volo.Abp.Data;
using Volo.Abp.Json.SystemTextJson;
+using Volo.Abp.ObjectExtending;
using Xunit;
namespace Volo.Abp.Json
@@ -78,6 +80,24 @@ namespace Volo.Abp.Json
newJson.ShouldBe("{\"name\":\"abp\",\"type\":2}");
}
+
+ [Fact]
+ public void Serialize_Deserialize_ExtensibleObject()
+ {
+ var json = "{\"name\":\"test\",\"extraProperties\":{\"One\":\"123\",\"Two\":456}}";
+ var extensibleObject = _jsonSerializer.Deserialize(json);
+ extensibleObject.GetProperty("One").ShouldBe("123");
+ extensibleObject.GetProperty("Two").ShouldBe(456);
+
+ var newJson = _jsonSerializer.Serialize(extensibleObject);
+ newJson.ShouldBe(json);
+ }
+
+ class TestExtensibleObjectClass : ExtensibleObject
+ {
+ public string Name { get; set; }
+ }
+
class FileWithBoolean
{
public string Name { get; set; }