From 401c6a9f4d2b1ae93ec144111fc2f9c05b06ec6e Mon Sep 17 00:00:00 2001 From: Andreas Date: Tue, 9 Jun 2026 13:19:12 +0200 Subject: [PATCH] Removed `Newtonsoft.Json` dependency Fixed #109 --- src/RestApiClientSharp.Test.NUnit/UnitTest.cs | 24 ++---- .../Models/Events/JsonConvertEventArgs.cs | 2 +- .../JSON/Newtonsoft/AbstractConverter.cs | 26 ------ .../JSON/System/TypeMappingConverter.cs | 2 +- .../Models/RestApiRequestRespone.cs | 2 +- .../RestApiClient.Clients.cs | 16 ++-- .../RestApiClient.JsonSerializer.cs | 8 +- .../RestApiClient.NewtonsoftJsonSerializer.cs | 80 ------------------- src/RestApiClientSharp/RestApiClient.Proxy.cs | 3 +- src/RestApiClientSharp/RestApiClient.Rest.cs | 2 +- .../RestApiClient.WebSocket.cs | 16 ++-- src/RestApiClientSharp/RestApiClient.cs | 6 +- .../RestApiClientSharp.csproj | 1 - .../RestApiConnectionBuilder.cs | 1 - .../RestSourceGenerationContext.cs | 12 ++- .../AuthenticationHeaderConverter.cs | 9 +++ 16 files changed, 55 insertions(+), 155 deletions(-) delete mode 100644 src/RestApiClientSharp/Models/JSON/Newtonsoft/AbstractConverter.cs delete mode 100644 src/RestApiClientSharp/RestApiClient.NewtonsoftJsonSerializer.cs create mode 100644 src/RestApiClientSharp/TypeConverters/AuthenticationHeaderConverter.cs diff --git a/src/RestApiClientSharp.Test.NUnit/UnitTest.cs b/src/RestApiClientSharp.Test.NUnit/UnitTest.cs index f3a094a..9921ef1 100644 --- a/src/RestApiClientSharp.Test.NUnit/UnitTest.cs +++ b/src/RestApiClientSharp.Test.NUnit/UnitTest.cs @@ -1,6 +1,8 @@ using AndreasReitberger.API.REST; using AndreasReitberger.API.REST.Enums; using AndreasReitberger.API.REST.Interfaces; +using AndreasReitberger.API.REST.SourceGeneration; +using AndreasReitberger.Shared.Core.Utilities; using Newtonsoft.Json; using RestApiClientSharp.Test.NUnit.Model; using RestSharp; @@ -42,32 +44,16 @@ public void Setup() #endregion #region JSON - [Test, Obsolete] - public void TestNewtonsoftJsonSerialization() - { - try - { - string? json = JsonConvert.SerializeObject(client, Formatting.Indented, settings: RestApiClient.DefaultNewtonsoftJsonSerializerSettings); - Assert.That(!string.IsNullOrEmpty(json)); - - RestApiClient? client2 = JsonConvert.DeserializeObject(json, settings: RestApiClient.DefaultNewtonsoftJsonSerializerSettings); - Assert.That(client2, Is.Not.Null); - } - catch (Exception ex) - { - Assert.Fail(ex.Message); - } - } [Test] public void TestJsonSerialization() { try { - string? json = System.Text.Json.JsonSerializer.Serialize(client, options: RestApiClient.DefaultJsonSerializerSettings); + string? json = System.Text.Json.JsonSerializer.Serialize(client, typeof(RestApiClient), context: RestSourceGenerationContext.Default); Assert.That(!string.IsNullOrEmpty(json)); - RestApiClient? client2 = System.Text.Json.JsonSerializer.Deserialize(json, options: RestApiClient.DefaultJsonSerializerSettings); + RestApiClient? client2 = (RestApiClient?)System.Text.Json.JsonSerializer.Deserialize(json, typeof(RestApiClient), context: RestSourceGenerationContext.Default); Assert.That(client2, Is.Not.Null); } catch (Exception ex) @@ -101,7 +87,7 @@ public async Task TestQueryAsync() .ConfigureAwait(false); json = result?.Result; Assert.That(!string.IsNullOrEmpty(json)); - TestJson? resultObject = client.GetObjectFromJsonSystem(json); + TestJson? resultObject = JsonConvertHelper.ToObject(json!, settings: RestSourceGenerationContext.Default); Assert.That(resultObject, Is.Not.Null); } catch (Exception ex) diff --git a/src/RestApiClientSharp/Models/Events/JsonConvertEventArgs.cs b/src/RestApiClientSharp/Models/Events/JsonConvertEventArgs.cs index fd5d7cf..9172191 100644 --- a/src/RestApiClientSharp/Models/Events/JsonConvertEventArgs.cs +++ b/src/RestApiClientSharp/Models/Events/JsonConvertEventArgs.cs @@ -9,7 +9,7 @@ public partial class JsonConvertEventArgs : EventArgs, IJsonConvertEventArgs public string? OriginalString { get; set; } public string? TargetType { get; set; } - [JsonIgnore, Newtonsoft.Json.JsonIgnore] + [JsonIgnore] public Exception? Exception { get; set; } #endregion diff --git a/src/RestApiClientSharp/Models/JSON/Newtonsoft/AbstractConverter.cs b/src/RestApiClientSharp/Models/JSON/Newtonsoft/AbstractConverter.cs deleted file mode 100644 index 169773f..0000000 --- a/src/RestApiClientSharp/Models/JSON/Newtonsoft/AbstractConverter.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Newtonsoft.Json; -using JsonConverter = Newtonsoft.Json.JsonConverter; -using JsonSerializer = Newtonsoft.Json.JsonSerializer; - -namespace AndreasReitberger.API.REST.JSON.Newtonsoft -{ - /// - /// Source: https://stackoverflow.com/a/48923314/10083577 - /// License: CC BY-SA 4.0 (https://creativecommons.org/licenses/by-sa/4.0/) - /// Author: Simone S. (https://stackoverflow.com/users/1255023/simone-s) - /// - /// - /// - public class AbstractConverter - : JsonConverter where TReal : TAbstract - { - public override bool CanConvert(Type objectType) - => objectType == typeof(TAbstract); - - public override object? ReadJson(JsonReader reader, Type type, object? value, JsonSerializer jser) - => jser.Deserialize(reader); - - public override void WriteJson(JsonWriter writer, object? value, JsonSerializer jser) - => jser.Serialize(writer, value); - } -} diff --git a/src/RestApiClientSharp/Models/JSON/System/TypeMappingConverter.cs b/src/RestApiClientSharp/Models/JSON/System/TypeMappingConverter.cs index 69e1601..8c1f615 100644 --- a/src/RestApiClientSharp/Models/JSON/System/TypeMappingConverter.cs +++ b/src/RestApiClientSharp/Models/JSON/System/TypeMappingConverter.cs @@ -13,7 +13,7 @@ namespace AndreasReitberger.API.REST.JSON.System /// /// - public sealed class TypeMappingConverter< + public class TypeMappingConverter< #if NET5_0_OR_GREATER [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | diff --git a/src/RestApiClientSharp/Models/RestApiRequestRespone.cs b/src/RestApiClientSharp/Models/RestApiRequestRespone.cs index 8fa3d1f..66ca8a6 100644 --- a/src/RestApiClientSharp/Models/RestApiRequestRespone.cs +++ b/src/RestApiClientSharp/Models/RestApiRequestRespone.cs @@ -25,7 +25,7 @@ public partial class RestApiRequestRespone : ObservableObject, IRestApiRequestRe public partial IRestEventArgs? EventArgs { get; set; } [ObservableProperty] - [JsonIgnore, Newtonsoft.Json.JsonIgnore] + [JsonIgnore] public partial Exception? Exception { get; set; } [ObservableProperty] diff --git a/src/RestApiClientSharp/RestApiClient.Clients.cs b/src/RestApiClientSharp/RestApiClient.Clients.cs index fc8276f..f0d0d4b 100644 --- a/src/RestApiClientSharp/RestApiClient.Clients.cs +++ b/src/RestApiClientSharp/RestApiClient.Clients.cs @@ -1,7 +1,5 @@ using AndreasReitberger.API.REST.Interfaces; using AndreasReitberger.API.REST.Utilities; -using Newtonsoft.Json; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.Net; using System.Net.Http; @@ -21,16 +19,16 @@ public partial class RestApiClient : ObservableObject, IRestApiClient #region Clients [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial RestClient? RestClient { get; set; } [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial HttpClient? HttpClient { get; set; } #if !NETFRAMEWORK [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial RateLimitedHandler? RateLimitedHandler { get; set; } public static RateLimiter DefaultLimiter = new TokenBucketRateLimiter(new() @@ -44,7 +42,7 @@ public partial class RestApiClient : ObservableObject, IRestApiClient }); [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial RateLimiter? Limiter { get; set; } partial void OnLimiterChanged(RateLimiter? value) => UpdateRestClientInstance(); #endif @@ -97,7 +95,11 @@ public virtual void UpdateRestClientInstance() RestClientOptions options = new(target) { +#if DEBUG + ThrowOnAnyError = true, +#else ThrowOnAnyError = false, +#endif Timeout = TimeSpan.FromSeconds(DefaultTimeout), CookieContainer = new CookieContainer(), }; @@ -134,6 +136,6 @@ public virtual void UpdateRestClientInstance() } UpdatingClients = false; } - #endregion +#endregion } } diff --git a/src/RestApiClientSharp/RestApiClient.JsonSerializer.cs b/src/RestApiClientSharp/RestApiClient.JsonSerializer.cs index 929a2d4..46db30f 100644 --- a/src/RestApiClientSharp/RestApiClient.JsonSerializer.cs +++ b/src/RestApiClientSharp/RestApiClient.JsonSerializer.cs @@ -9,11 +9,11 @@ public partial class RestApiClient : ObservableObject, IRestApiClient { [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, JsonIgnore, XmlIgnore] - public partial JsonSerializerOptions JsonSerializerSettings { get; set; } = DefaultJsonSerializerSettings; + [JsonIgnore, XmlIgnore] + public partial JsonSerializerOptions JsonSerializerSettings { get; set; } = RestSourceGenerationContext.Default.Options; #region SerializerSettings - + [Obsolete("This property is deprecated. Use the `RestSourceGenerationContext` instead.")] public static JsonSerializerOptions DefaultJsonSerializerSettings = new() { TypeInfoResolver = RestSourceGenerationContext.Default, @@ -34,6 +34,7 @@ public partial class RestApiClient : ObservableObject, IRestApiClient #region Methods #nullable enable + [Obsolete("This method is deprecated. Use the `JsonConvertHelper.ToObject` method from the `SharedNetCoreLibrary` instead.")] public T? GetObjectFromJsonSystem(string? json, JsonSerializerContext serializerContext) { try @@ -53,6 +54,7 @@ public partial class RestApiClient : ObservableObject, IRestApiClient return default; } } + [Obsolete("This method is deprecated. Use the `JsonConvertHelper.ToObject` method from the `SharedNetCoreLibrary` instead.")] public T? GetObjectFromJsonSystem(string? json, JsonSerializerOptions? serializerSettings = null) { try diff --git a/src/RestApiClientSharp/RestApiClient.NewtonsoftJsonSerializer.cs b/src/RestApiClientSharp/RestApiClient.NewtonsoftJsonSerializer.cs deleted file mode 100644 index 3030392..0000000 --- a/src/RestApiClientSharp/RestApiClient.NewtonsoftJsonSerializer.cs +++ /dev/null @@ -1,80 +0,0 @@ -using AndreasReitberger.API.REST.Events; -using AndreasReitberger.API.REST.Interfaces; -using AndreasReitberger.API.REST.JSON.Newtonsoft; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -#if NET5_0_OR_GREATER -using System.Diagnostics.CodeAnalysis; -#endif - -namespace AndreasReitberger.API.REST -{ - public partial class RestApiClient : ObservableObject, IRestApiClient - { - [ObservableProperty] - [Obsolete("Due to trimming use `System.Json.JsonSerializerSettings` implementations")] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] - public partial JsonSerializerSettings NewtonsoftJsonSerializerSettings { get; set; } = DefaultNewtonsoftJsonSerializerSettings; - - #region SerializerSettings - [Obsolete("Due to trimming use `System.Json.JsonSerializerSettings` implementations")] -#if NET5_0_OR_GREATER - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] -#endif - public static JsonSerializerSettings DefaultNewtonsoftJsonSerializerSettings = new() - { - Formatting = Formatting.Indented, - ContractResolver = new DefaultContractResolver - { - NamingStrategy = new CamelCaseNamingStrategy(), - }, - DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffK", - // Detect if the json respone has more or less properties than the target class - //MissingMemberHandling = MissingMemberHandling.Error, -#if DEBUG - MissingMemberHandling = MissingMemberHandling.Ignore, - NullValueHandling = NullValueHandling.Include, -#else - // Ignore if the json respone has more or less properties than the target class - MissingMemberHandling = MissingMemberHandling.Ignore, - NullValueHandling = NullValueHandling.Ignore, -#endif - TypeNameHandling = TypeNameHandling.Auto, - Converters = - { - // Map the converters - new AbstractConverter(), - } - }; - #endregion - - #region Methods - -#nullable enable - [Obsolete("Due to trimming use `System.Json.JsonSerializerSettings` implementations")] -#if NET5_0_OR_GREATER - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] -#endif - public T? GetObjectFromJson(string? json, JsonSerializerSettings? serializerSettings = null) - { - try - { - json ??= string.Empty; - return JsonConvert.DeserializeObject(json, serializerSettings ?? NewtonsoftJsonSerializerSettings); - } - catch (JsonSerializationException jexc) - { - OnError(new JsonConvertEventArgs() - { - Exception = jexc, - OriginalString = json, - Message = jexc?.Message, - TargetType = nameof(T) - }); - return default; - } - } -#nullable disable - #endregion - } -} \ No newline at end of file diff --git a/src/RestApiClientSharp/RestApiClient.Proxy.cs b/src/RestApiClientSharp/RestApiClient.Proxy.cs index 6371276..b2d74ed 100644 --- a/src/RestApiClientSharp/RestApiClient.Proxy.cs +++ b/src/RestApiClientSharp/RestApiClient.Proxy.cs @@ -1,5 +1,4 @@ using AndreasReitberger.API.REST.Interfaces; -using Newtonsoft.Json; using System.Net; namespace AndreasReitberger.API.REST @@ -37,7 +36,7 @@ public partial class RestApiClient : ObservableObject, IRestApiClient partial void OnProxyUserChanged(string value) => UpdateRestClientInstance(); [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial string? ProxyPassword { get; set; } partial void OnProxyPasswordChanged(string? value) => UpdateRestClientInstance(); diff --git a/src/RestApiClientSharp/RestApiClient.Rest.cs b/src/RestApiClientSharp/RestApiClient.Rest.cs index 1e8bc5d..014ad4a 100644 --- a/src/RestApiClientSharp/RestApiClient.Rest.cs +++ b/src/RestApiClientSharp/RestApiClient.Rest.cs @@ -35,7 +35,7 @@ protected virtual bool GetQueryResult(string? result, bool emptyResultIsValid = { if ((string.IsNullOrEmpty(result) || result == "{}") && emptyResultIsValid) return true; - return GetObjectFromJsonSystem(result)?.Ok ?? false; + return JsonConvertHelper.ToObject(result!, settings: RestSourceGenerationContext.Default)?.Ok ?? false; } catch (Exception exc) { diff --git a/src/RestApiClientSharp/RestApiClient.WebSocket.cs b/src/RestApiClientSharp/RestApiClient.WebSocket.cs index d8117a9..469abf3 100644 --- a/src/RestApiClientSharp/RestApiClient.WebSocket.cs +++ b/src/RestApiClientSharp/RestApiClient.WebSocket.cs @@ -22,15 +22,15 @@ public partial class RestApiClient : ObservableObject, IRestApiClient #region Properties [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial WebsocketClient? WebSocket { get; set; } [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial CancellationTokenSource? CtsPinging { get; set; } [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial bool IsListening { get; set; } = false; partial void OnIsListeningChanged(bool value) { @@ -43,7 +43,7 @@ partial void OnIsListeningChanged(bool value) } [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial Func? OnRefresh { get; set; } [ObservableProperty] @@ -57,7 +57,7 @@ partial void OnRefreshIntervalChanged(int value) } [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial long LastPingTimestamp { get; set; } [ObservableProperty] @@ -74,15 +74,15 @@ partial void OnPingIntervalChanged(int value) } [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial long PingCounter { get; set; } = 0; [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial long LastRefreshTimestamp { get; set; } [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial int RefreshCounter { get; set; } = 0; [ObservableProperty] diff --git a/src/RestApiClientSharp/RestApiClient.cs b/src/RestApiClientSharp/RestApiClient.cs index d28d20a..e1fbf26 100644 --- a/src/RestApiClientSharp/RestApiClient.cs +++ b/src/RestApiClientSharp/RestApiClient.cs @@ -29,15 +29,15 @@ public partial class RestApiClient : ObservableObject, IRestApiClient public partial bool IsActive { get; set; } = false; [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial bool IsConnecting { get; set; } = false; [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial bool IsOnline { get; set; } = false; [ObservableProperty] - [Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore, XmlIgnore] + [JsonIgnore, XmlIgnore] public partial bool IsAccessTokenValid { get; set; } = false; [ObservableProperty] diff --git a/src/RestApiClientSharp/RestApiClientSharp.csproj b/src/RestApiClientSharp/RestApiClientSharp.csproj index 5b9adc9..7c950b7 100644 --- a/src/RestApiClientSharp/RestApiClientSharp.csproj +++ b/src/RestApiClientSharp/RestApiClientSharp.csproj @@ -12,7 +12,6 @@ - diff --git a/src/RestApiClientSharp/RestApiConnectionBuilder.cs b/src/RestApiClientSharp/RestApiConnectionBuilder.cs index fc579cd..9d5268a 100644 --- a/src/RestApiClientSharp/RestApiConnectionBuilder.cs +++ b/src/RestApiClientSharp/RestApiConnectionBuilder.cs @@ -1,5 +1,4 @@ using AndreasReitberger.API.REST.Interfaces; -using Newtonsoft.Json; using System.Collections.Generic; using System.Threading.RateLimiting; diff --git a/src/RestApiClientSharp/SourceGeneration/RestSourceGenerationContext.cs b/src/RestApiClientSharp/SourceGeneration/RestSourceGenerationContext.cs index f60236c..44befa9 100644 --- a/src/RestApiClientSharp/SourceGeneration/RestSourceGenerationContext.cs +++ b/src/RestApiClientSharp/SourceGeneration/RestSourceGenerationContext.cs @@ -1,4 +1,5 @@ using AndreasReitberger.API.REST.Events; +using AndreasReitberger.API.REST.TypeConverters; namespace AndreasReitberger.API.REST.SourceGeneration { @@ -15,6 +16,15 @@ namespace AndreasReitberger.API.REST.SourceGeneration [JsonSerializable(typeof(TaskCanceledEventArgs))] [JsonSerializable(typeof(WebsocketEventArgs))] [JsonSerializable(typeof(WebsocketPingSentEventArgs))] - [JsonSourceGenerationOptions(WriteIndented = true)] + [JsonSourceGenerationOptions(WriteIndented = true, + Converters = new Type[] { + typeof(AuthenticationHeaderConverter), + }, ReferenceHandler = +#if DEBUG + JsonKnownReferenceHandler.Preserve +#else + JsonKnownReferenceHandler.IgnoreCycles +#endif + )] public partial class RestSourceGenerationContext : JsonSerializerContext { } } diff --git a/src/RestApiClientSharp/TypeConverters/AuthenticationHeaderConverter.cs b/src/RestApiClientSharp/TypeConverters/AuthenticationHeaderConverter.cs new file mode 100644 index 0000000..67c2912 --- /dev/null +++ b/src/RestApiClientSharp/TypeConverters/AuthenticationHeaderConverter.cs @@ -0,0 +1,9 @@ +using AndreasReitberger.API.REST.Interfaces; +using AndreasReitberger.API.REST.JSON.System; + +namespace AndreasReitberger.API.REST.TypeConverters +{ + public class AuthenticationHeaderConverter : TypeMappingConverter + { + } +}