From 8e97f5f1ea501afb27fce1c462bb0966d3a100bb Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 20 Nov 2019 19:59:06 +0800 Subject: Migrate to System.Text.Json . Format enum to string instead of number. Use ISO8601 format for datetime. --- Timeline.Tests/Helpers/ResponseAssertions.cs | 25 +++++++++++++++++++--- .../Models/Converters/JsonDateTimeConverter.cs | 23 ++++++++++++++++++++ Timeline/Models/Http/Common.cs | 4 ++++ Timeline/Startup.cs | 16 +++++++++----- 4 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 Timeline/Models/Converters/JsonDateTimeConverter.cs diff --git a/Timeline.Tests/Helpers/ResponseAssertions.cs b/Timeline.Tests/Helpers/ResponseAssertions.cs index 6d764c68..301ceef6 100644 --- a/Timeline.Tests/Helpers/ResponseAssertions.cs +++ b/Timeline.Tests/Helpers/ResponseAssertions.cs @@ -2,11 +2,13 @@ using FluentAssertions.Execution; using FluentAssertions.Formatting; using FluentAssertions.Primitives; -using Newtonsoft.Json; using System; using System.Net; using System.Net.Http; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Timeline.Models.Converters; using Timeline.Models.Http; namespace Timeline.Tests.Helpers @@ -88,8 +90,25 @@ namespace Timeline.Tests.Helpers return new AndWhichConstraint(this, null); } - var result = JsonConvert.DeserializeObject(body); // TODO! catch and throw on bad format - return new AndWhichConstraint(this, result); + + try + { + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + options.Converters.Add(new JsonStringEnumConverter()); + options.Converters.Add(new JsonDateTimeConverter()); + + var result = JsonSerializer.Deserialize(body, options); + + return new AndWhichConstraint(this, result); + } + catch (JsonException e) + { + a.FailWith("Expected response body of {context:HttpResponseMessage} to be json string{reason}, but failed to deserialize it. Exception is {0}.", e); + return new AndWhichConstraint(this, null); + } } } diff --git a/Timeline/Models/Converters/JsonDateTimeConverter.cs b/Timeline/Models/Converters/JsonDateTimeConverter.cs new file mode 100644 index 00000000..551bbbaa --- /dev/null +++ b/Timeline/Models/Converters/JsonDateTimeConverter.cs @@ -0,0 +1,23 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Timeline.Models.Converters +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods")] + public class JsonDateTimeConverter : JsonConverter + { + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + Debug.Assert(typeToConvert == typeof(DateTime)); + return DateTime.Parse(reader.GetString(), CultureInfo.InvariantCulture); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture)); + } + } +} diff --git a/Timeline/Models/Http/Common.cs b/Timeline/Models/Http/Common.cs index 2a88b3a3..d1e95397 100644 --- a/Timeline/Models/Http/Common.cs +++ b/Timeline/Models/Http/Common.cs @@ -72,6 +72,8 @@ namespace Timeline.Models.Http { public class ResponseData { + public ResponseData() { } + public ResponseData(bool create) { Create = create; @@ -106,6 +108,8 @@ namespace Timeline.Models.Http { public class ResponseData { + public ResponseData() { } + public ResponseData(bool delete) { Delete = delete; diff --git a/Timeline/Startup.cs b/Timeline/Startup.cs index b2e958f9..672e5f15 100644 --- a/Timeline/Startup.cs +++ b/Timeline/Startup.cs @@ -8,11 +8,13 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System.Collections.Generic; using System.Globalization; +using System.Text.Json.Serialization; using Timeline.Auth; using Timeline.Configs; using Timeline.Entities; using Timeline.Formatters; using Timeline.Helpers; +using Timeline.Models.Converters; using Timeline.Services; namespace Timeline @@ -36,11 +38,15 @@ namespace Timeline { setup.InputFormatters.Add(new StringInputFormatter()); }) - .ConfigureApiBehaviorOptions(options => - { - options.InvalidModelStateResponseFactory = InvalidModelResponseFactory.Factory; - }) - .AddNewtonsoftJson(); // TODO: Remove this. + .AddJsonOptions(options => + { + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + options.JsonSerializerOptions.Converters.Add(new JsonDateTimeConverter()); + }) + .ConfigureApiBehaviorOptions(options => + { + options.InvalidModelStateResponseFactory = InvalidModelResponseFactory.Factory; + }); services.Configure(Configuration.GetSection(nameof(JwtConfig))); var jwtConfig = Configuration.GetSection(nameof(JwtConfig)).Get(); -- cgit v1.2.3 From c74d95b029caaf4f69977179823ebefb6f88029a Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 20 Nov 2019 20:06:40 +0800 Subject: Add test for bad enum value of timeline visibility. --- Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs b/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs index 483499fb..c5d0addd 100644 --- a/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs +++ b/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs @@ -169,6 +169,12 @@ namespace Timeline.Tests.IntegratedTests { const string userUrl = "users/user/timeline/posts"; const string adminUrl = "users/admin/timeline/posts"; + { + using var client = await CreateClientAsUser(); + var res = await client.PostAsync("users/user/timeline/op/property", + new StringContent(@"{""visibility"":""abcdefg""}", System.Text.Encoding.UTF8, System.Net.Mime.MediaTypeNames.Application.Json)); + res.Should().BeInvalidModel(); + } { // default visibility is registered { using var client = await CreateClientWithNoAuth(); -- cgit v1.2.3