diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs index 9777265abd..4fc5a04859 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs @@ -20,6 +20,8 @@ public static class MvcCoreBuilderExtensions options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory()); options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); + options.JsonSerializerOptions.Converters.Add(new AbpStringToGuidConverter()); + options.JsonSerializerOptions.Converters.Add(new AbpNullableStringToGuidConverter()); options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); options.JsonSerializerOptions.TypeInfoResolver = new AbpDefaultJsonTypeInfoResolver(serviceProvider diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs index 50dd47d9e2..f6ef46a4e7 100644 --- a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs @@ -22,6 +22,8 @@ public class AbpJsonSystemTextJsonModule : AbpModule options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory()); options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); + options.JsonSerializerOptions.Converters.Add(new AbpStringToGuidConverter()); + options.JsonSerializerOptions.Converters.Add(new AbpNullableStringToGuidConverter()); options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); options.JsonSerializerOptions.TypeInfoResolver = new AbpDefaultJsonTypeInfoResolver(serviceProvider diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableStringToGuidConverter.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableStringToGuidConverter.cs new file mode 100644 index 0000000000..c80e5aa9a5 --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableStringToGuidConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Volo.Abp.Json.SystemTextJson.JsonConverters; + +public class AbpNullableStringToGuidConverter : JsonConverter +{ + private JsonSerializerOptions _writeJsonSerializerOptions; + + public override Guid? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + var guidString = reader.GetString(); + string[] formats = { "N", "D", "B", "P", "X" }; + foreach (var format in formats) + { + if (Guid.TryParseExact(guidString, format, out var guid)) + { + return guid; + } + } + } + + if (reader.TryGetGuid(out var guid2)) + { + return guid2; + } + + return null; + } + + public override void Write(Utf8JsonWriter writer, Guid? value, JsonSerializerOptions options) + { + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this); + var entityConverter = (JsonConverter)_writeJsonSerializerOptions.GetConverter(typeof(Guid?)); + + entityConverter.Write(writer, value, _writeJsonSerializerOptions); + } +} diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToGuidConverter.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToGuidConverter.cs new file mode 100644 index 0000000000..586e4462cf --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToGuidConverter.cs @@ -0,0 +1,36 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Volo.Abp.Json.SystemTextJson.JsonConverters; + +public class AbpStringToGuidConverter : JsonConverter +{ + private JsonSerializerOptions _writeJsonSerializerOptions; + + public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + var guidString = reader.GetString(); + string[] formats = { "N", "D", "B", "P", "X" }; + foreach (var format in formats) + { + if (Guid.TryParseExact(guidString, format, out var guid)) + { + return guid; + } + } + } + + return reader.GetGuid(); + } + + public override void Write(Utf8JsonWriter writer, Guid value, JsonSerializerOptions options) + { + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this); + var entityConverter = (JsonConverter)_writeJsonSerializerOptions.GetConverter(typeof(Guid)); + + entityConverter.Write(writer, value, _writeJsonSerializerOptions); + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs index 471d33261a..6dfe3a7281 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs @@ -49,6 +49,12 @@ public class ModelBindingController : AbpController input.Time3.Value.Kind.ToString().ToLower() + "_" + input.InnerModel.Time4.Kind.ToString().ToLower(); } + + [HttpPost("Guid_Json_Test")] + public GuidJsonModel Guid_Json_Test([FromBody] GuidJsonModel input) + { + return input; + } } public class GetDateTimeKindModel @@ -68,3 +74,20 @@ public class GetDateTimeKindModel public DateTime Time4 { get; set; } } } + +public class GuidJsonModel +{ + public Guid UserId { get; set; } + + public Guid UserId2 { get; set; } + + public Guid UserId3 { get; set; } + + public Guid UserId4 { get; set; } + + public Guid UserId5 { get; set; } + + public Guid? TenantId { get; set; } + + public Guid? TenantId2 { get; set; } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs index befbd169fa..53bfff8b68 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs @@ -106,6 +106,18 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase var resultAsString = await response.Content.ReadAsStringAsync(); resultAsString.ShouldBe($"local_{Kind.ToString().ToLower()}_{Kind.ToString().ToLower()}_local"); } + + [Fact] + public async Task Guid_Json_Test() + { + var guid = Guid.NewGuid(); + var json = $"{{\"UserId\":\"{guid:B}\",\"UserId2\":\"{guid:N}\",\"UserId3\":\"{guid:D}\",\"UserId4\":\"{guid:P}\",\"UserId5\":\"{guid:x}\",\"TenantId\":null,\"TenantId2\":\"\"}}"; + var response = await Client.PostAsync("/api/model-Binding-test/Guid_Json_Test", new StringContent(json, Encoding.UTF8, MimeTypes.Application.Json)); + + response.StatusCode.ShouldBe(HttpStatusCode.OK); + var resultAsString = await response.Content.ReadAsStringAsync(); + resultAsString.ShouldBe($"{{\"userId\":\"{guid:D}\",\"userId2\":\"{guid:D}\",\"userId3\":\"{guid:D}\",\"userId4\":\"{guid:D}\",\"userId5\":\"{guid:D}\",\"tenantId\":null,\"tenantId2\":null}}"); + } } public class ModelBindingController_Utc_Tests : ModelBindingController_Tests diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToGuid_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToGuid_Tests.cs new file mode 100644 index 0000000000..93918b48c1 --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToGuid_Tests.cs @@ -0,0 +1,85 @@ +using System; +using System.Text.Json; +using Shouldly; +using Volo.Abp.Json.SystemTextJson.JsonConverters; +using Xunit; + +namespace Volo.Abp.Json; + +public class AbpStringToGuid_Tests +{ + [Fact] + public void Test_Read() + { + var options = new JsonSerializerOptions() + { + Converters = + { + new AbpStringToGuidConverter(), + new AbpNullableStringToGuidConverter() + } + }; + + var guid = Guid.Parse("762DDB84-5225-4853-A566-FF0B3AF57585"); + var testClass = JsonSerializer.Deserialize("{" + + $"\"Id\": \"{guid:N}\", " + + $"\"NullableId\": \"{guid:D}\", " + + $"\"NullableId2\": \"{guid:B}\", " + + $"\"NullableId3\": \"{guid:P}\", " + + $"\"NullableId4\": \"{guid:X}\", " + + "\"NullableId5\": \"\", " + + "\"NullableId6\": null}", options); + testClass.ShouldNotBeNull(); + testClass.Id.ShouldBe(guid); + testClass.NullableId.ShouldBe(guid); + testClass.NullableId2.ShouldBe(guid); + testClass.NullableId3.ShouldBe(guid); + testClass.NullableId4.ShouldBe(guid); + testClass.NullableId5.ShouldBeNull(); + testClass.NullableId6.ShouldBeNull(); + } + + [Fact] + public void Test_Write() + { + var options = new JsonSerializerOptions() + { + Converters = + { + new AbpStringToGuidConverter(), + new AbpNullableStringToGuidConverter() + } + }; + + var guid = Guid.Parse("762DDB84-5225-4853-A566-FF0B3AF57585"); + var json = JsonSerializer.Serialize(new TestClass() + { + Id = guid, + NullableId = null, + NullableId2 = guid, + NullableId3 = null, + NullableId4 = guid, + NullableId5 = null, + NullableId6 = guid + }, options); + + json.ShouldBe($"{{\"Id\":\"{guid:D}\",\"NullableId\":null,\"NullableId2\":\"{guid:D}\",\"NullableId3\":null,\"NullableId4\":\"{guid:D}\",\"NullableId5\":null,\"NullableId6\":\"{guid:D}\"}}"); + } + + class TestClass + { + public Guid Id { get; set; } + + public Guid? NullableId { get; set; } + + public Guid? NullableId2 { get; set; } + + public Guid? NullableId3 { get; set; } + + public Guid? NullableId4 { get; set; } + + public Guid? NullableId5 { get; set; } + + public Guid? NullableId6 { get; set; } + } +}