diff --git a/Transmission.API.RPC/Client.cs b/Transmission.API.RPC/Client.cs index 654d135..9fc7ad6 100644 --- a/Transmission.API.RPC/Client.cs +++ b/Transmission.API.RPC/Client.cs @@ -18,17 +18,6 @@ namespace Transmission.API.RPC /// public partial class Client : ITransmissionClient { - /// - /// Provides default JSON serialization options with case-insensitive property name matching. - /// - /// These options configure the JSON serializer to ignore case when matching property - /// names during serialization and deserialization. This can improve compatibility when working with JSON data - /// that may use different casing conventions. - private static readonly JsonSerializerOptions _jsonOptions = new() - { - PropertyNameCaseInsensitive = true - }; - /// /// Authorization header value for requests /// @@ -192,7 +181,7 @@ public async Task GetSessionStatisticAsync() { var request = new TransmissionRequest("session-stats"); var response = await SendRequestAsync(request); - var result = response.Deserialize(); + var result = response.Deserialize(TransmissionJsonArgumentsContext.Default.Statistic); return result; } @@ -205,7 +194,7 @@ public async Task GetSessionInformationAsync() { var request = new TransmissionRequest("session-get"); var response = await SendRequestAsync(request); - var result = response.Deserialize(); + var result = response.Deserialize(TransmissionJsonArgumentsContext.Default.SessionInfo); return result; } @@ -228,16 +217,16 @@ public async Task TorrentAddAsync(NewTorrent torrent) if (response.Arguments == null) return null; - var json = JsonSerializer.Serialize(response.Arguments); + var json = JsonSerializer.Serialize(response.Arguments, TransmissionJsonArgumentsContext.Default.DictionaryStringObject); using var doc = JsonDocument.Parse(json); var root = doc.RootElement; NewTorrentInfo result = null; if (root.TryGetProperty("torrent-duplicate", out var dupValue)) - result = JsonSerializer.Deserialize(dupValue.GetRawText()); + result = JsonSerializer.Deserialize(dupValue.GetRawText(), TransmissionJsonArgumentsContext.Default.NewTorrentInfo); else if (root.TryGetProperty("torrent-added", out var addValue)) - result = JsonSerializer.Deserialize(addValue.GetRawText()); + result = JsonSerializer.Deserialize(addValue.GetRawText(), TransmissionJsonArgumentsContext.Default.NewTorrentInfo); return result; } @@ -269,7 +258,7 @@ public async Task TorrentGetAsync(string[] fields, params var request = new TransmissionRequest("torrent-get", arguments); var response = await SendRequestAsync(request); - var result = response.Deserialize(); + var result = response.Deserialize(TransmissionJsonArgumentsContext.Default.TransmissionTorrents); return result; } @@ -454,7 +443,7 @@ public async Task TorrentRenamePathAsync(int id, string path, var request = new TransmissionRequest("torrent-rename-path", arguments); var response = await SendRequestAsync(request); - var result = response.Deserialize(); + var result = response.Deserialize(TransmissionJsonArgumentsContext.Default.RenameTorrentInfo); return result; } @@ -472,7 +461,7 @@ public async Task PortTestAsync() var request = new TransmissionRequest("port-test"); var response = await SendRequestAsync(request); - var json = JsonSerializer.Serialize(response.Arguments); + var json = JsonSerializer.Serialize(response.Arguments, TransmissionJsonArgumentsContext.Default.DictionaryStringObject); using var doc = JsonDocument.Parse(json); return doc.RootElement.GetProperty("port-is-open").GetBoolean(); } @@ -486,7 +475,7 @@ public async Task BlocklistUpdateAsync() var request = new TransmissionRequest("blocklist-update"); var response = await SendRequestAsync(request); - var json = JsonSerializer.Serialize(response.Arguments); + var json = JsonSerializer.Serialize(response.Arguments, TransmissionJsonArgumentsContext.Default.DictionaryStringObject); using var doc = JsonDocument.Parse(json); return doc.RootElement.GetProperty("blocklist-size").GetInt32(); } @@ -503,7 +492,7 @@ public async Task FreeSpaceAsync(string path) var request = new TransmissionRequest("free-space", arguments); var response = await SendRequestAsync(request); - var json = JsonSerializer.Serialize(response.Arguments); + var json = JsonSerializer.Serialize(response.Arguments, TransmissionJsonArgumentsContext.Default.DictionaryStringObject); using var doc = JsonDocument.Parse(json); return doc.RootElement.GetProperty("size-bytes").GetInt64(); } @@ -547,14 +536,14 @@ private async Task SendRequestAsync(TransmissionRequest re if (_needAuthorization) httpRequest.Headers.Add("Authorization", _authorization); - httpRequest.Content = new StringContent(request.ToJson(), Encoding.UTF8, "application/json-rpc"); + httpRequest.Content = new StringContent(request.ToRpcJson(), Encoding.UTF8, "application/json-rpc"); using (var httpResponse = await _httpClient.SendAsync(httpRequest)) { if (httpResponse.IsSuccessStatusCode) { var responseString = await httpResponse.Content.ReadAsStringAsync(); - var result = JsonSerializer.Deserialize(responseString, _jsonOptions); + var result = JsonSerializer.Deserialize(responseString, TransmissionJsonResponseContext.Default.TransmissionResponse); if (result.Result != "success") throw new Exception(result.Result); diff --git a/Transmission.API.RPC/Common/CommunicateBase.cs b/Transmission.API.RPC/Common/CommunicateBase.cs index 24aa08f..cf47aba 100644 --- a/Transmission.API.RPC/Common/CommunicateBase.cs +++ b/Transmission.API.RPC/Common/CommunicateBase.cs @@ -1,6 +1,9 @@ using System.Collections.Generic; +using System; +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; namespace Transmission.API.RPC.Common { @@ -30,6 +33,8 @@ public abstract class CommunicateBase /// Convert to JSON string /// /// + [RequiresUnreferencedCode("Use a source-generated JsonTypeInfo overload for trimming and Native AOT.")] + [RequiresDynamicCode("Use a source-generated JsonTypeInfo overload for Native AOT.")] public virtual string ToJson() { return JsonSerializer.Serialize(this, GetType(), _indentedOptions); @@ -39,10 +44,22 @@ public virtual string ToJson() /// Deserialize to class /// /// + [RequiresUnreferencedCode("Use Deserialize(JsonTypeInfo) with source-generated metadata for trimming and Native AOT.")] + [RequiresDynamicCode("Use Deserialize(JsonTypeInfo) with source-generated metadata for Native AOT.")] public T Deserialize() { var argumentsString = JsonSerializer.Serialize(Arguments); return JsonSerializer.Deserialize(argumentsString); } + + /// + /// Deserialize to class + /// + /// + public T Deserialize(JsonTypeInfo jsonTypeInfo) + { + var argumentsString = JsonSerializer.Serialize(Arguments, TransmissionJsonArgumentsContext.Default.DictionaryStringObject); + return JsonSerializer.Deserialize(argumentsString, jsonTypeInfo); + } } } diff --git a/Transmission.API.RPC/Common/TransmissionJsonArgumentsContext.cs b/Transmission.API.RPC/Common/TransmissionJsonArgumentsContext.cs new file mode 100644 index 0000000..1071d8c --- /dev/null +++ b/Transmission.API.RPC/Common/TransmissionJsonArgumentsContext.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; +using Transmission.API.RPC.Entity; + +namespace Transmission.API.RPC.Common +{ + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(JsonElement))] + [JsonSerializable(typeof(object))] + [JsonSerializable(typeof(object[]))] + [JsonSerializable(typeof(string))] + [JsonSerializable(typeof(string[]))] + [JsonSerializable(typeof(int))] + [JsonSerializable(typeof(int[]))] + [JsonSerializable(typeof(long))] + [JsonSerializable(typeof(long[]))] + [JsonSerializable(typeof(bool))] + [JsonSerializable(typeof(bool[]))] + [JsonSerializable(typeof(double))] + [JsonSerializable(typeof(double[]))] + [JsonSerializable(typeof(float))] + [JsonSerializable(typeof(float[]))] + [JsonSerializable(typeof(decimal))] + [JsonSerializable(typeof(decimal[]))] + [JsonSerializable(typeof(Units))] + [JsonSerializable(typeof(NewTorrentInfo))] + [JsonSerializable(typeof(RenameTorrentInfo))] + [JsonSerializable(typeof(SessionInfo))] + [JsonSerializable(typeof(Statistic))] + [JsonSerializable(typeof(TransmissionTorrents))] + internal partial class TransmissionJsonArgumentsContext : JsonSerializerContext + { + } +} diff --git a/Transmission.API.RPC/Common/TransmissionJsonResponseContext.cs b/Transmission.API.RPC/Common/TransmissionJsonResponseContext.cs new file mode 100644 index 0000000..a342019 --- /dev/null +++ b/Transmission.API.RPC/Common/TransmissionJsonResponseContext.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Transmission.API.RPC.Common +{ + [JsonSourceGenerationOptions(PropertyNameCaseInsensitive = true)] + [JsonSerializable(typeof(TransmissionResponse))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(JsonElement))] + [JsonSerializable(typeof(object))] + internal partial class TransmissionJsonResponseContext : JsonSerializerContext + { + } +} diff --git a/Transmission.API.RPC/Common/TransmissionJsonWriteContext.cs b/Transmission.API.RPC/Common/TransmissionJsonWriteContext.cs new file mode 100644 index 0000000..f5b9f84 --- /dev/null +++ b/Transmission.API.RPC/Common/TransmissionJsonWriteContext.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; +using Transmission.API.RPC.Entity; + +namespace Transmission.API.RPC.Common +{ + [JsonSourceGenerationOptions(WriteIndented = true)] + [JsonSerializable(typeof(TransmissionRequest))] + [JsonSerializable(typeof(TransmissionResponse))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(JsonElement))] + [JsonSerializable(typeof(object))] + [JsonSerializable(typeof(object[]))] + [JsonSerializable(typeof(string))] + [JsonSerializable(typeof(string[]))] + [JsonSerializable(typeof(int))] + [JsonSerializable(typeof(int[]))] + [JsonSerializable(typeof(long))] + [JsonSerializable(typeof(long[]))] + [JsonSerializable(typeof(bool))] + [JsonSerializable(typeof(bool[]))] + [JsonSerializable(typeof(double))] + [JsonSerializable(typeof(double[]))] + [JsonSerializable(typeof(float))] + [JsonSerializable(typeof(float[]))] + [JsonSerializable(typeof(decimal))] + [JsonSerializable(typeof(decimal[]))] + [JsonSerializable(typeof(Units))] + internal partial class TransmissionJsonWriteContext : JsonSerializerContext + { + } +} diff --git a/Transmission.API.RPC/Common/TransmissionRequest.cs b/Transmission.API.RPC/Common/TransmissionRequest.cs index 773245d..de3145f 100644 --- a/Transmission.API.RPC/Common/TransmissionRequest.cs +++ b/Transmission.API.RPC/Common/TransmissionRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Text.Json; using System.Text.Json.Serialization; namespace Transmission.API.RPC.Common @@ -18,9 +19,14 @@ public class TransmissionRequest : CommunicateBase /// Initialize request /// /// Method name - public TransmissionRequest(string method) + public TransmissionRequest(string method) + { + this.Method = method; + } + + internal string ToRpcJson() { - this.Method = method; + return JsonSerializer.Serialize(this, TransmissionJsonWriteContext.Default.TransmissionRequest); } /// diff --git a/Transmission.API.RPC/Transmission.API.RPC.csproj b/Transmission.API.RPC/Transmission.API.RPC.csproj index af16611..12a9452 100644 --- a/Transmission.API.RPC/Transmission.API.RPC.csproj +++ b/Transmission.API.RPC/Transmission.API.RPC.csproj @@ -21,6 +21,7 @@ false + true true true snupkg