Migrate from newtonsoft.json to system.text.json

This commit is contained in:
Zoe Roux 2024-03-22 21:20:47 +01:00
parent d7e5b8b916
commit ad9d1ee430
No known key found for this signature in database
4 changed files with 136 additions and 177 deletions

View File

@ -19,6 +19,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using AspNetCore.Proxy; using AspNetCore.Proxy;
using Autofac; using Autofac;
using Kyoo.Abstractions; using Kyoo.Abstractions;
@ -30,10 +32,6 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using JsonOptions = Kyoo.Core.Api.JsonOptions;
namespace Kyoo.Core namespace Kyoo.Core
{ {
@ -86,7 +84,6 @@ namespace Kyoo.Core
public void Configure(IServiceCollection services) public void Configure(IServiceCollection services)
{ {
services.AddHttpContextAccessor(); services.AddHttpContextAccessor();
services.AddTransient<IConfigureOptions<MvcNewtonsoftJsonOptions>, JsonOptions>();
services services
.AddMvcCore(options => .AddMvcCore(options =>
@ -96,10 +93,11 @@ namespace Kyoo.Core
options.ModelBinderProviders.Insert(0, new IncludeBinder.Provider()); options.ModelBinderProviders.Insert(0, new IncludeBinder.Provider());
options.ModelBinderProviders.Insert(0, new FilterBinder.Provider()); options.ModelBinderProviders.Insert(0, new FilterBinder.Provider());
}) })
.AddNewtonsoftJson(x => .AddJsonOptions(x =>
{ {
x.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; x.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
x.SerializerSettings.Converters.Add(new StringEnumConverter()); x.JsonSerializerOptions.TypeInfoResolver = new PolymorphicTypeResolver();
x.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
}) })
.AddDataAnnotations() .AddDataAnnotations()
.AddControllersAsServices() .AddControllersAsServices()

View File

@ -1,55 +0,0 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Kyoo.Core.Api
{
/// <summary>
/// The custom options of newtonsoft json. This simply add the <see cref="PeopleRoleConverter"/> and set
/// the <see cref="JsonSerializerContract"/>. It is on a separate class to use dependency injection.
/// </summary>
public class JsonOptions : IConfigureOptions<MvcNewtonsoftJsonOptions>
{
/// <summary>
/// The http context accessor given to the <see cref="JsonSerializerContract"/>.
/// </summary>
private readonly IHttpContextAccessor _httpContextAccessor;
/// <summary>
/// Create a new <see cref="JsonOptions"/>.
/// </summary>
/// <param name="httpContextAccessor">
/// The http context accessor given to the <see cref="JsonSerializerContract"/>.
/// </param>
public JsonOptions(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
/// <inheritdoc />
public void Configure(MvcNewtonsoftJsonOptions options)
{
options.SerializerSettings.ContractResolver = new JsonSerializerContract(
_httpContextAccessor
);
}
}
}

View File

@ -1,117 +1,69 @@
// Kyoo - A portable and vast media library solution. // // Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo. // // Copyright (c) Kyoo.
// //
// // See AUTHORS.md and LICENSE file in the project root for full license information.
// //
// // Kyoo is free software: you can redistribute it and/or modify
// // it under the terms of the GNU General Public License as published by
// // the Free Software Foundation, either version 3 of the License, or
// // any later version.
// //
// // Kyoo is distributed in the hope that it will be useful,
// // but WITHOUT ANY WARRANTY; without even the implied warranty of
// // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// // GNU General Public License for more details.
// //
// // You should have received a copy of the GNU General Public License
// // along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
// //
// See AUTHORS.md and LICENSE file in the project root for full license information. // using System;
// using System.Collections.Generic;
// using System.Linq;
// using System.Net.Http.Formatting;
// using System.Reflection;
// using Kyoo.Abstractions.Models;
// using Kyoo.Abstractions.Models.Attributes;
// using Microsoft.AspNetCore.Http;
// using static System.Text.Json.JsonNamingPolicy;
// //
// Kyoo is free software: you can redistribute it and/or modify // namespace Kyoo.Core.Api
// it under the terms of the GNU General Public License as published by // {
// the Free Software Foundation, either version 3 of the License, or // /// <summary>
// any later version. // /// A custom json serializer that respects <see cref="SerializeIgnoreAttribute"/> and
// /// <see cref="DeserializeIgnoreAttribute"/>. It also handle <see cref="LoadableRelationAttribute"/> via the
// /// <c>fields</c> query parameter and <see cref="IThumbnails"/> items.
// /// </summary>
// public class JsonSerializerContract(IHttpContextAccessor? httpContextAccessor, MediaTypeFormatter formatter)
// : JsonContractResolver(formatter)
// {
// /// <inheritdoc />
// protected override JsonProperty CreateProperty(
// MemberInfo member,
// MemberSerialization memberSerialization
// )
// {
// JsonProperty property = base.CreateProperty(member, memberSerialization);
// //
// Kyoo is distributed in the hope that it will be useful, // LoadableRelationAttribute? relation =
// but WITHOUT ANY WARRANTY; without even the implied warranty of // member.GetCustomAttribute<LoadableRelationAttribute>();
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // if (relation != null)
// GNU General Public License for more details. // {
// // if (httpContextAccessor != null)
// You should have received a copy of the GNU General Public License // {
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>. // property.ShouldSerialize = _ =>
// {
using System; // if (
using System.Collections.Generic; // httpContextAccessor.HttpContext!.Items["fields"]
using System.Linq; // is not ICollection<string> fields
using System.Reflection; // )
using Kyoo.Abstractions.Models; // return false;
using Kyoo.Abstractions.Models.Attributes; // return fields.Contains(member.Name);
using Microsoft.AspNetCore.Http; // };
using Newtonsoft.Json; // }
using Newtonsoft.Json.Serialization; // else
using static System.Text.Json.JsonNamingPolicy; // property.ShouldSerialize = _ => true;
// }
namespace Kyoo.Core.Api // return property;
{ // }
/// <summary> // }
/// A custom json serializer that respects <see cref="SerializeIgnoreAttribute"/> and // }
/// <see cref="DeserializeIgnoreAttribute"/>. It also handle <see cref="LoadableRelationAttribute"/> via the
/// <c>fields</c> query parameter and <see cref="IThumbnails"/> items.
/// </summary>
public class JsonSerializerContract : CamelCasePropertyNamesContractResolver
{
/// <summary>
/// The http context accessor used to retrieve the <c>fields</c> query parameter as well as the type of
/// resource currently serializing.
/// </summary>
private readonly IHttpContextAccessor _httpContextAccessor;
/// <summary>
/// Create a new <see cref="JsonSerializerContract"/>.
/// </summary>
/// <param name="httpContextAccessor">The http context accessor to use.</param>
public JsonSerializerContract(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
/// <inheritdoc />
protected override JsonProperty CreateProperty(
MemberInfo member,
MemberSerialization memberSerialization
)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
LoadableRelationAttribute? relation =
member.GetCustomAttribute<LoadableRelationAttribute>();
if (relation != null)
{
property.ShouldSerialize = _ =>
{
if (
_httpContextAccessor.HttpContext!.Items["fields"]
is not ICollection<string> fields
)
return false;
return fields.Contains(member.Name);
};
}
return property;
}
protected override IList<JsonProperty> CreateProperties(
Type type,
MemberSerialization memberSerialization
)
{
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
if (
properties.All(x => x.PropertyName != "kind")
&& type.IsAssignableTo(typeof(IResource))
)
{
properties.Add(
new JsonProperty()
{
DeclaringType = type,
PropertyName = "kind",
UnderlyingName = "kind",
PropertyType = typeof(string),
ValueProvider = new FixedValueProvider(CamelCase.ConvertName(type.Name)),
Readable = true,
Writable = false,
TypeNameHandling = TypeNameHandling.None,
}
);
}
return properties;
}
public class FixedValueProvider(object value) : IValueProvider
{
public object GetValue(object target) => value;
public void SetValue(object target, object? value) =>
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,64 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Kyoo.Abstractions.Models;
using static System.Text.Json.JsonNamingPolicy;
namespace Kyoo.Core.Api;
public class PolymorphicTypeResolver : DefaultJsonTypeInfoResolver
{
private static readonly IList<JsonDerivedType> _types = AppDomain
.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => p.IsAssignableTo(typeof(IResource)) && p.IsClass)
.Select(x => new JsonDerivedType(x, CamelCase.ConvertName(x.Name)))
.ToList();
public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
{
JsonTypeInfo jsonTypeInfo = base.GetTypeInfo(type, options);
if (
jsonTypeInfo.Type.IsAssignableTo(typeof(IResource))
&& jsonTypeInfo.Properties.All(x => x.Name != "kind")
)
{
jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions
{
TypeDiscriminatorPropertyName = "kind",
IgnoreUnrecognizedTypeDiscriminators = true,
UnknownDerivedTypeHandling =
JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor,
DerivedTypes = { },
};
Console.WriteLine(string.Join(",", _types.Select(x => x.DerivedType.Name)));
foreach (JsonDerivedType derived in _types)
jsonTypeInfo.PolymorphismOptions.DerivedTypes.Add(derived);
}
return jsonTypeInfo;
}
}