New: Use System.Text.Json for Nancy and SignalR
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
This commit is contained in:
parent
2e953a0eb1
commit
f50b54b3f6
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
@ -38,12 +39,61 @@ namespace NzbDrone.Common.Serializer
|
|||
public static T Deserialize<T>(string json)
|
||||
where T : new()
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(json, SerializerSettings);
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(json, SerializerSettings);
|
||||
}
|
||||
catch (JsonReaderException ex)
|
||||
{
|
||||
throw DetailedJsonReaderException(ex, json);
|
||||
}
|
||||
}
|
||||
|
||||
public static object Deserialize(string json, Type type)
|
||||
{
|
||||
return JsonConvert.DeserializeObject(json, type, SerializerSettings);
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject(json, type, SerializerSettings);
|
||||
}
|
||||
catch (JsonReaderException ex)
|
||||
{
|
||||
throw DetailedJsonReaderException(ex, json);
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonReaderException DetailedJsonReaderException(JsonReaderException ex, string json)
|
||||
{
|
||||
var lineNumber = ex.LineNumber == 0 ? 0 : (ex.LineNumber - 1);
|
||||
var linePosition = ex.LinePosition;
|
||||
|
||||
var lines = json.Split('\n');
|
||||
if (lineNumber >= 0 && lineNumber < lines.Length &&
|
||||
linePosition >= 0 && linePosition < lines[lineNumber].Length)
|
||||
{
|
||||
var line = lines[lineNumber];
|
||||
var start = Math.Max(0, linePosition - 20);
|
||||
var end = Math.Min(line.Length, linePosition + 20);
|
||||
|
||||
var snippetBefore = line.Substring(start, linePosition - start);
|
||||
var snippetAfter = line.Substring(linePosition, end - linePosition);
|
||||
var message = ex.Message + " (Json snippet '" + snippetBefore + "<--error-->" + snippetAfter + "')";
|
||||
|
||||
// Not risking updating JSON.net from 9.x to 10.x just to get this as public ctor.
|
||||
var ctor = typeof(JsonReaderException).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(Exception), typeof(string), typeof(int), typeof(int) }, null);
|
||||
if (ctor != null)
|
||||
{
|
||||
return (JsonReaderException)ctor.Invoke(new object[] { message, ex, ex.Path, ex.LineNumber, linePosition });
|
||||
}
|
||||
|
||||
// JSON.net 10.x ctor in case we update later.
|
||||
ctor = typeof(JsonReaderException).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(string), typeof(int), typeof(int), typeof(Exception) }, null);
|
||||
if (ctor != null)
|
||||
{
|
||||
return (JsonReaderException)ctor.Invoke(new object[] { message, ex.Path, ex.LineNumber, linePosition, ex });
|
||||
}
|
||||
}
|
||||
|
||||
return ex;
|
||||
}
|
||||
|
||||
public static bool TryDeserialize<T>(string json, out T result)
|
||||
|
@ -77,10 +127,5 @@ namespace NzbDrone.Common.Serializer
|
|||
Serializer.Serialize(jsonTextWriter, model);
|
||||
jsonTextWriter.Flush();
|
||||
}
|
||||
|
||||
public static void Serialize<TModel>(TModel model, Stream outputStream)
|
||||
{
|
||||
Serialize(model, new StreamWriter(outputStream));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
@ -9,7 +9,7 @@ namespace NzbDrone.Core.Profiles.Qualities
|
|||
{
|
||||
public class QualityProfileQualityItem : IEmbeddedDocument
|
||||
{
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
|
|
|
@ -11,8 +11,7 @@ using NzbDrone.Core.Messaging.Events;
|
|||
namespace NzbDrone.Core.ThingiProvider
|
||||
{
|
||||
public class ProviderRepository<TProviderDefinition> : BasicRepository<TProviderDefinition>, IProviderRepository<TProviderDefinition>
|
||||
where TProviderDefinition : ProviderDefinition,
|
||||
new()
|
||||
where TProviderDefinition : ProviderDefinition, new()
|
||||
{
|
||||
protected readonly JsonSerializerOptions _serializerSettings;
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Owin" Version="6.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="6.0.0" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -108,9 +108,9 @@ namespace NzbDrone.Host
|
|||
{
|
||||
services
|
||||
.AddSignalR()
|
||||
.AddNewtonsoftJsonProtocol(options =>
|
||||
.AddJsonProtocol(options =>
|
||||
{
|
||||
options.PayloadSerializerSettings = Json.GetSerializerSettings();
|
||||
options.PayloadSerializerOptions = STJson.GetSerializerSettings();
|
||||
});
|
||||
})
|
||||
.Configure(app =>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using Newtonsoft.Json;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
|
||||
namespace NzbDrone.SignalR
|
||||
|
@ -8,7 +7,7 @@ namespace NzbDrone.SignalR
|
|||
public object Body { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public ModelAction Action { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.CustomFilters;
|
||||
|
@ -10,7 +11,7 @@ namespace Sonarr.Api.V3.CustomFilters
|
|||
{
|
||||
public string Type { get; set; }
|
||||
public string Label { get; set; }
|
||||
public List<dynamic> Filters { get; set; }
|
||||
public List<ExpandoObject> Filters { get; set; }
|
||||
}
|
||||
|
||||
public static class CustomFilterResourceMapper
|
||||
|
@ -23,12 +24,12 @@ namespace Sonarr.Api.V3.CustomFilters
|
|||
}
|
||||
|
||||
return new CustomFilterResource
|
||||
{
|
||||
Id = model.Id,
|
||||
Type = model.Type,
|
||||
Label = model.Label,
|
||||
Filters = Json.Deserialize<List<dynamic>>(model.Filters)
|
||||
};
|
||||
{
|
||||
Id = model.Id,
|
||||
Type = model.Type,
|
||||
Label = model.Label,
|
||||
Filters = STJson.Deserialize<List<ExpandoObject>>(model.Filters)
|
||||
};
|
||||
}
|
||||
|
||||
public static CustomFilter ToModel(this CustomFilterResource resource)
|
||||
|
@ -39,12 +40,12 @@ namespace Sonarr.Api.V3.CustomFilters
|
|||
}
|
||||
|
||||
return new CustomFilter
|
||||
{
|
||||
Id = resource.Id,
|
||||
Type = resource.Type,
|
||||
Label = resource.Label,
|
||||
Filters = Json.ToJson(resource.Filters)
|
||||
};
|
||||
{
|
||||
Id = resource.Id,
|
||||
Type = resource.Type,
|
||||
Label = resource.Label,
|
||||
Filters = STJson.ToJson(resource.Filters)
|
||||
};
|
||||
}
|
||||
|
||||
public static List<CustomFilterResource> ToResource(this IEnumerable<CustomFilter> filters)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
@ -68,14 +68,10 @@ namespace Sonarr.Api.V3.Indexers
|
|||
|
||||
// Sent when queuing an unknown release
|
||||
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
|
||||
// [JsonIgnore]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int? SeriesId { get; set; }
|
||||
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
|
||||
// [JsonIgnore]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int? EpisodeId { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
<PackageReference Include="Nancy" Version="2.0.0" />
|
||||
<PackageReference Include="Nancy.Authentication.Basic" Version="2.0.0" />
|
||||
<PackageReference Include="Nancy.Authentication.Forms" Version="2.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="NLog" Version="4.7.14" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Core.Update;
|
||||
using Sonarr.Http.REST;
|
||||
|
||||
|
@ -9,7 +8,6 @@ namespace Sonarr.Api.V3.Update
|
|||
{
|
||||
public class UpdateResource : RestResource
|
||||
{
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.VersionConverter))]
|
||||
public Version Version { get; set; }
|
||||
|
||||
public string Branch { get; set; }
|
||||
|
|
|
@ -2,10 +2,11 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Text.Json;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Reflection;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Annotations;
|
||||
|
||||
namespace Sonarr.Http.ClientSchema
|
||||
|
@ -216,9 +217,9 @@ namespace Sonarr.Http.ClientSchema
|
|||
{
|
||||
return Enumerable.Empty<int>();
|
||||
}
|
||||
else if (fieldValue.GetType() == typeof(JArray))
|
||||
else if (fieldValue is JsonElement e && e.ValueKind == JsonValueKind.Array)
|
||||
{
|
||||
return ((JArray)fieldValue).Select(s => s.Value<int>());
|
||||
return e.EnumerateArray().Select(s => s.GetInt32());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -234,9 +235,9 @@ namespace Sonarr.Http.ClientSchema
|
|||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
else if (fieldValue.GetType() == typeof(JArray))
|
||||
else if (fieldValue is JsonElement e && e.ValueKind == JsonValueKind.Array)
|
||||
{
|
||||
return ((JArray)fieldValue).Select(s => s.Value<string>());
|
||||
return e.EnumerateArray().Select(s => s.GetString());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -246,7 +247,18 @@ namespace Sonarr.Http.ClientSchema
|
|||
}
|
||||
else
|
||||
{
|
||||
return fieldValue => fieldValue;
|
||||
return fieldValue =>
|
||||
{
|
||||
var element = fieldValue as JsonElement?;
|
||||
|
||||
if (element == null || !element.HasValue)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var json = element.Value.GetRawText();
|
||||
return STJson.Deserialize(json, propertyType);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Nancy;
|
||||
using Nancy.Responses.Negotiation;
|
||||
using NzbDrone.Common.Serializer;
|
||||
|
@ -8,6 +9,13 @@ namespace Sonarr.Http.Extensions
|
|||
{
|
||||
public class NancyJsonSerializer : ISerializer
|
||||
{
|
||||
protected readonly JsonSerializerOptions _serializerSettings;
|
||||
|
||||
public NancyJsonSerializer()
|
||||
{
|
||||
_serializerSettings = STJson.GetSerializerSettings();
|
||||
}
|
||||
|
||||
public bool CanSerialize(MediaRange contentType)
|
||||
{
|
||||
return contentType == "application/json";
|
||||
|
@ -15,7 +23,7 @@ namespace Sonarr.Http.Extensions
|
|||
|
||||
public void Serialize<TModel>(MediaRange contentType, TModel model, Stream outputStream)
|
||||
{
|
||||
Json.Serialize(model, outputStream);
|
||||
STJson.Serialize(model, outputStream, _serializerSettings);
|
||||
}
|
||||
|
||||
public IEnumerable<string> Extensions { get; private set; }
|
||||
|
|
|
@ -28,10 +28,8 @@ namespace Sonarr.Http.Extensions
|
|||
|
||||
public static object FromJson(this Stream body, Type type)
|
||||
{
|
||||
var reader = new StreamReader(body, true);
|
||||
body.Position = 0;
|
||||
var value = reader.ReadToEnd();
|
||||
return Json.Deserialize(value, type);
|
||||
return STJson.Deserialize(body, type);
|
||||
}
|
||||
|
||||
public static JsonResponse<TModel> AsResponse<TModel>(this TModel model, NancyContext context, HttpStatusCode statusCode = HttpStatusCode.OK)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using Nancy;
|
||||
using Nancy.Responses.Negotiation;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using Sonarr.Http.Extensions;
|
||||
|
||||
|
@ -233,7 +233,7 @@ namespace Sonarr.Http.REST
|
|||
{
|
||||
resource = Request.Body.FromJson<TResource>();
|
||||
}
|
||||
catch (JsonReaderException e)
|
||||
catch (JsonException e)
|
||||
{
|
||||
throw new BadRequestException($"Invalid request body. {e.Message}");
|
||||
}
|
||||
|
@ -330,7 +330,6 @@ namespace Sonarr.Http.REST
|
|||
}
|
||||
|
||||
// v3 uses filters in key=value format
|
||||
|
||||
foreach (var key in Request.Query)
|
||||
{
|
||||
if (_excludedKeys.Contains(key))
|
||||
|
@ -339,10 +338,10 @@ namespace Sonarr.Http.REST
|
|||
}
|
||||
|
||||
pagingResource.Filters.Add(new PagingResourceFilter
|
||||
{
|
||||
Key = key,
|
||||
Value = Request.Query[key]
|
||||
});
|
||||
{
|
||||
Key = key,
|
||||
Value = Request.Query[key]
|
||||
});
|
||||
}
|
||||
|
||||
return pagingResource;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Sonarr.Http.REST
|
||||
{
|
||||
public abstract class RestResource
|
||||
{
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public int Id { get; set; }
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public virtual int Id { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public virtual string ResourceName => GetType().Name.ToLowerInvariant().Replace("resource", "");
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
<PackageReference Include="Nancy" Version="2.0.0" />
|
||||
<PackageReference Include="Nancy.Authentication.Basic" Version="2.0.0" />
|
||||
<PackageReference Include="Nancy.Authentication.Forms" Version="2.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="NLog" Version="4.7.14" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
Loading…
Reference in New Issue