mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
JsonSerializer: Cleaning up fields handling
This commit is contained in:
parent
fd50a2dedc
commit
1cd88a8bfe
@ -26,7 +26,6 @@ using Autofac.Extras.AttributeMetadata;
|
||||
using Kyoo.Abstractions;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models.Utils;
|
||||
using Kyoo.Core.Api;
|
||||
using Kyoo.Core.Controllers;
|
||||
using Kyoo.Core.Models.Options;
|
||||
using Kyoo.Core.Tasks;
|
||||
@ -35,11 +34,12 @@ using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Serilog;
|
||||
using IMetadataProvider = Kyoo.Abstractions.Controllers.IMetadataProvider;
|
||||
using JsonOptions = Kyoo.Core.Api.JsonOptions;
|
||||
|
||||
namespace Kyoo.Core
|
||||
{
|
||||
@ -67,20 +67,6 @@ namespace Kyoo.Core
|
||||
{ "logging", null }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The configuration to use.
|
||||
/// </summary>
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new core module instance and use the given configuration.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration to use</param>
|
||||
public CoreModule(IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(ContainerBuilder builder)
|
||||
{
|
||||
@ -140,17 +126,13 @@ namespace Kyoo.Core
|
||||
/// <inheritdoc />
|
||||
public void Configure(IServiceCollection services)
|
||||
{
|
||||
Uri publicUrl = _configuration.GetPublicUrl();
|
||||
services.AddTransient<IConfigureOptions<MvcNewtonsoftJsonOptions>, JsonOptions>();
|
||||
|
||||
services.AddMvcCore()
|
||||
.AddNewtonsoftJson()
|
||||
.AddDataAnnotations()
|
||||
.AddControllersAsServices()
|
||||
.AddApiExplorer()
|
||||
.AddNewtonsoftJson(x =>
|
||||
{
|
||||
x.SerializerSettings.ContractResolver = new JsonPropertyIgnorer(publicUrl);
|
||||
x.SerializerSettings.Converters.Add(new PeopleRoleConverter());
|
||||
})
|
||||
.ConfigureApiBehaviorOptions(options =>
|
||||
{
|
||||
options.SuppressMapClientErrors = true;
|
||||
|
@ -24,6 +24,7 @@ using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
using Kyoo.Abstractions.Models.Utils;
|
||||
using Kyoo.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
@ -64,13 +65,13 @@ namespace Kyoo.Core.Api
|
||||
type = Utility.GetGenericDefinition(type, typeof(ActionResult<>))?.GetGenericArguments()[0] ?? type;
|
||||
type = Utility.GetGenericDefinition(type, typeof(Page<>))?.GetGenericArguments()[0] ?? type;
|
||||
|
||||
context.HttpContext.Items["ResourceType"] = type.Name;
|
||||
|
||||
PropertyInfo[] properties = type.GetProperties()
|
||||
.Where(x => x.GetCustomAttribute<LoadableRelationAttribute>() != null)
|
||||
.ToArray();
|
||||
if (fields.Count == 1 && fields.Contains("all"))
|
||||
{
|
||||
fields = properties.Select(x => x.Name).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
fields = fields
|
||||
@ -82,10 +83,9 @@ namespace Kyoo.Core.Api
|
||||
?.Name;
|
||||
if (property != null)
|
||||
return property;
|
||||
context.Result = new BadRequestObjectResult(new
|
||||
{
|
||||
Error = $"{x} does not exist on {type.Name}."
|
||||
});
|
||||
context.Result = new BadRequestObjectResult(
|
||||
new RequestError($"{x} does not exist on {type.Name}.")
|
||||
);
|
||||
return null;
|
||||
})
|
||||
.ToList();
|
||||
@ -110,7 +110,7 @@ namespace Kyoo.Core.Api
|
||||
if (result.DeclaredType == null)
|
||||
return;
|
||||
|
||||
ILibraryManager library = context.HttpContext.RequestServices.GetService<ILibraryManager>();
|
||||
ILibraryManager library = context.HttpContext.RequestServices.GetRequiredService<ILibraryManager>();
|
||||
ICollection<string> fields = (ICollection<string>)context.HttpContext.Items["fields"];
|
||||
Type pageType = Utility.GetGenericDefinition(result.DeclaredType, typeof(Page<>));
|
||||
|
||||
@ -119,13 +119,13 @@ namespace Kyoo.Core.Api
|
||||
foreach (IResource resource in ((dynamic)result.Value).Items)
|
||||
{
|
||||
foreach (string field in fields!)
|
||||
await library!.Load(resource, field);
|
||||
await library.Load(resource, field);
|
||||
}
|
||||
}
|
||||
else if (result.DeclaredType.IsAssignableTo(typeof(IResource)))
|
||||
{
|
||||
foreach (string field in fields!)
|
||||
await library!.Load((IResource)result.Value, field);
|
||||
await library.Load((IResource)result.Value, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
54
src/Kyoo.Core/Views/Helper/Serializers/JsonOptions.cs
Normal file
54
src/Kyoo.Core/Views/Helper/Serializers/JsonOptions.cs
Normal file
@ -0,0 +1,54 @@
|
||||
// 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);
|
||||
options.SerializerSettings.Converters.Add(new PeopleRoleConverter());
|
||||
}
|
||||
}
|
||||
}
|
@ -16,27 +16,39 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
using Kyoo.Utils;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Kyoo.Core.Api
|
||||
{
|
||||
public class JsonPropertyIgnorer : CamelCasePropertyNamesContractResolver
|
||||
/// <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
|
||||
{
|
||||
private readonly Uri _host;
|
||||
private int _depth = -1;
|
||||
/// <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;
|
||||
|
||||
public JsonPropertyIgnorer(Uri host)
|
||||
/// <summary>
|
||||
/// Create a new <see cref="JsonSerializerContract"/>.
|
||||
/// </summary>
|
||||
/// <param name="httpContextAccessor">The http context accessor to use.</param>
|
||||
public JsonSerializerContract(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_host = host;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
|
||||
{
|
||||
JsonProperty property = base.CreateProperty(member, memberSerialization);
|
||||
@ -44,19 +56,14 @@ namespace Kyoo.Core.Api
|
||||
LoadableRelationAttribute relation = member.GetCustomAttribute<LoadableRelationAttribute>();
|
||||
if (relation != null)
|
||||
{
|
||||
if (relation.RelationID == null)
|
||||
property.ShouldSerialize = x => _depth == 0 && member.GetValue(x) != null;
|
||||
else
|
||||
property.ShouldSerialize = _ =>
|
||||
{
|
||||
property.ShouldSerialize = x =>
|
||||
{
|
||||
if (_depth != 0)
|
||||
return false;
|
||||
if (member.GetValue(x) != null)
|
||||
return true;
|
||||
return x.GetType().GetProperty(relation.RelationID)?.GetValue(x) != null;
|
||||
};
|
||||
}
|
||||
string resType = (string)_httpContextAccessor.HttpContext!.Items["ResourceType"];
|
||||
if (member.DeclaringType!.Name != resType)
|
||||
return false;
|
||||
ICollection<string> fields = (ICollection<string>)_httpContextAccessor.HttpContext!.Items["fields"];
|
||||
return fields!.Contains(member.Name);
|
||||
};
|
||||
}
|
||||
|
||||
if (member.GetCustomAttribute<SerializeIgnoreAttribute>() != null)
|
||||
@ -66,24 +73,10 @@ namespace Kyoo.Core.Api
|
||||
|
||||
// TODO use http context to disable serialize as.
|
||||
// TODO check https://stackoverflow.com/questions/53288633/net-core-api-custom-json-resolver-based-on-request-values
|
||||
SerializeAsAttribute serializeAs = member.GetCustomAttribute<SerializeAsAttribute>();
|
||||
if (serializeAs != null)
|
||||
property.ValueProvider = new SerializeAsProvider(serializeAs.Format, _host);
|
||||
// SerializeAsAttribute serializeAs = member.GetCustomAttribute<SerializeAsAttribute>();
|
||||
// if (serializeAs != null)
|
||||
// property.ValueProvider = new SerializeAsProvider(serializeAs.Format, _host);
|
||||
return property;
|
||||
}
|
||||
|
||||
protected override JsonContract CreateContract(Type objectType)
|
||||
{
|
||||
JsonContract contract = base.CreateContract(objectType);
|
||||
if (Utility.GetGenericDefinition(objectType, typeof(Page<>)) == null
|
||||
&& !objectType.IsAssignableTo(typeof(IEnumerable))
|
||||
&& objectType.Name != "AnnotatedProblemDetails")
|
||||
{
|
||||
contract.OnSerializingCallbacks.Add((_, _) => _depth++);
|
||||
contract.OnSerializedCallbacks.Add((_, _) => _depth--);
|
||||
}
|
||||
|
||||
return contract;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<LangVersion>default</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<Authors>Zoe Roux</Authors>
|
||||
<Company>SDG</Company>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -37,5 +33,4 @@
|
||||
<ProjectReference Include="../../src/Kyoo.Core/Kyoo.Core.csproj" />
|
||||
<ProjectReference Include="../../src/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
Loading…
x
Reference in New Issue
Block a user