diff --git a/Consul.Test/ACLTest.cs b/Consul.Test/ACLTest.cs index 2b9d3cf4b..6efdef98f 100644 --- a/Consul.Test/ACLTest.cs +++ b/Consul.Test/ACLTest.cs @@ -29,7 +29,7 @@ public class ACLTest : BaseFixture async Task SkipIfAclNotSupportedAsync() { var info = await _client.Agent.Self(); - var version = new Version(info.Response["Config"]["Version"]); + var version = new Version(info.Response["Config"]["Version"].GetString()); Skip.If(version >= new Version("1.11.0"), "Legacy ACL system was removed in Consul 1.11."); } diff --git a/Consul.Test/AgentTest.cs b/Consul.Test/AgentTest.cs index 66530f24f..206fe6211 100644 --- a/Consul.Test/AgentTest.cs +++ b/Consul.Test/AgentTest.cs @@ -34,8 +34,8 @@ public async Task Agent_GetSelf() var info = await _client.Agent.Self(); Assert.NotNull(info); - Assert.False(string.IsNullOrEmpty(info.Response["Config"]["NodeName"])); - Assert.False(string.IsNullOrEmpty(info.Response["Member"]["Tags"]["bootstrap"].ToString())); + Assert.False(string.IsNullOrEmpty(info.Response["Config"]["NodeName"].GetString())); + Assert.False(string.IsNullOrEmpty(info.Response["Member"]["Tags"].GetProperty("bootstrap").GetString())); } [Fact] @@ -411,7 +411,7 @@ public async Task Agent_Checks_ServiceBound() public async Task Agent_Join() { var info = await _client.Agent.Self(); - await _client.Agent.Join(info.Response["DebugConfig"]["AdvertiseAddrLAN"], false); + await _client.Agent.Join(info.Response["DebugConfig"]["AdvertiseAddrLAN"].GetString(), false); // Success is not throwing an exception } @@ -419,7 +419,7 @@ public async Task Agent_Join() public async Task Agent_ForceLeave() { var info = await _client.Agent.Self(); - await _client.Agent.ForceLeave(info.Response["Config"]["NodeName"]); + await _client.Agent.ForceLeave(info.Response["Config"]["NodeName"].GetString()); // Success is not throwing an exception } diff --git a/Consul.Test/Consul.Test.csproj b/Consul.Test/Consul.Test.csproj index e7db40a5b..f8727a8be 100644 --- a/Consul.Test/Consul.Test.csproj +++ b/Consul.Test/Consul.Test.csproj @@ -23,7 +23,6 @@ - diff --git a/Consul.Test/HealthTest.cs b/Consul.Test/HealthTest.cs index eff6cab3b..d948dbba7 100644 --- a/Consul.Test/HealthTest.cs +++ b/Consul.Test/HealthTest.cs @@ -30,7 +30,7 @@ public class HealthTest : BaseFixture public async Task Health_GetLocalNode() { var info = await _client.Agent.Self(); - var checks = await _client.Health.Node((string)info.Response["Config"]["NodeName"]); + var checks = await _client.Health.Node(info.Response["Config"]["NodeName"].GetString()); Assert.NotEqual((ulong)0, checks.LastIndex); Assert.NotEmpty(checks.Response); diff --git a/Consul/ACL.cs b/Consul/ACL.cs index 07f1fe33e..0e382b0e8 100644 --- a/Consul/ACL.cs +++ b/Consul/ACL.cs @@ -18,9 +18,10 @@ // ----------------------------------------------------------------------- using System; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -80,23 +81,14 @@ public override int GetHashCode() } [Obsolete("The Legacy ACL system has been deprecated, please use Token, Role and Policy instead.")] - public class ACLTypeConverter : JsonConverter + public class ACLTypeConverter : JsonConverter { -#pragma warning disable CS0809 // Obsolete member 'ACLType.Equals(object)' overrides non-obsolete member - [Obsolete("The Legacy ACL system has been deprecated, please use Token, Role and Policy instead.")] - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) -#pragma warning restore CS0809 // Obsolete member 'ACLType.Equals(object)' overrides non-obsolete member - { - serializer.Serialize(writer, ((ACLType)value).Type); - } - -#pragma warning disable CS0809 // Obsolete member 'ACLType.Equals(object)' overrides non-obsolete member +#pragma warning disable CS0809 [Obsolete("The Legacy ACL system has been deprecated, please use Token, Role and Policy instead.")] - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) -#pragma warning restore CS0809 // Obsolete member 'ACLType.Equals(object)' overrides non-obsolete member + public override ACLType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) +#pragma warning restore CS0809 { - var type = (string)serializer.Deserialize(reader, typeof(string)); + var type = reader.GetString(); switch (type) { case "client": @@ -104,21 +96,17 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist case "management": return ACLType.Management; default: - throw new ArgumentOutOfRangeException("serializer", type, + throw new ArgumentOutOfRangeException(nameof(type), type, "Unknown ACL token type value found during deserialization"); } } -#pragma warning disable CS0809 // Obsolete member 'ACLType.Equals(object)' overrides non-obsolete member +#pragma warning disable CS0809 [Obsolete("The Legacy ACL system has been deprecated, please use Token, Role and Policy instead.")] - public override bool CanConvert(Type objectType) -#pragma warning restore CS0809 // Obsolete member 'ACLType.Equals(object)' overrides non-obsolete member + public override void Write(Utf8JsonWriter writer, ACLType value, JsonSerializerOptions options) +#pragma warning restore CS0809 { - if (objectType == typeof(ACLType)) - { - return true; - } - return false; + writer.WriteStringValue(value.Type); } } @@ -139,7 +127,7 @@ public class ACLEntry [Obsolete("The Legacy ACL system has been deprecated, please use Token, Role and Policy instead.")] [JsonConverter(typeof(ACLTypeConverter))] - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ACLType Type { get; set; } [Obsolete("The Legacy ACL system has been deprecated, please use Token, Role and Policy instead.")] @@ -192,12 +180,6 @@ internal ACL(ConsulClient c) _client = c; } - private class ACLCreationResult - { - [JsonProperty] - internal string ID { get; set; } - } - /// /// [Deprecated] Create is used to generate a new token with the given parameters /// @@ -218,8 +200,8 @@ private class ACLCreationResult [Obsolete("The Legacy ACL system has been deprecated, please use Token, Role and Policy instead.")] public async Task> Create(ACLEntry acl, WriteOptions q, CancellationToken ct = default(CancellationToken)) { - var res = await _client.Put("/v1/acl/create", acl, q).Execute(ct).ConfigureAwait(false); - return new WriteResult(res, res.Response.ID); + var res = await _client.Put("/v1/acl/create", acl, q).Execute(ct).ConfigureAwait(false); + return new WriteResult(res, res.Response.GetProperty("ID").GetString()); } /// @@ -288,8 +270,8 @@ private class ACLCreationResult [Obsolete("The Legacy ACL system has been deprecated, please use Token, Role and Policy instead.")] public async Task> Clone(string id, WriteOptions q, CancellationToken ct = default(CancellationToken)) { - var res = await _client.PutReturning(string.Format("/v1/acl/clone/{0}", id), q).Execute(ct).ConfigureAwait(false); - return new WriteResult(res, res.Response.ID); + var res = await _client.PutReturning(string.Format("/v1/acl/clone/{0}", id), q).Execute(ct).ConfigureAwait(false); + return new WriteResult(res, res.Response.GetProperty("ID").GetString()); } /// diff --git a/Consul/ACLReplication.cs b/Consul/ACLReplication.cs index 5cc7e2675..44fde2bd7 100644 --- a/Consul/ACLReplication.cs +++ b/Consul/ACLReplication.cs @@ -17,9 +17,9 @@ // ----------------------------------------------------------------------- using System; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { diff --git a/Consul/Agent.cs b/Consul/Agent.cs index f811e22bc..a49242958 100644 --- a/Consul/Agent.cs +++ b/Consul/Agent.cs @@ -21,10 +21,11 @@ using System.Collections; using System.Collections.Generic; using System.IO; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using Consul.Filtering; -using Newtonsoft.Json; namespace Consul { @@ -70,18 +71,11 @@ public override int GetHashCode() /// /// TLS Status Convertor (to and from JSON) /// - public class TTLStatusConverter : JsonConverter + public class TTLStatusConverter : JsonConverter { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override TTLStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - serializer.Serialize(writer, ((TTLStatus)value).Status); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) - { - var status = (string)serializer.Deserialize(reader, typeof(string)); - switch (status) + switch (reader.GetString()) { case "pass": return TTLStatus.Pass; @@ -100,9 +94,9 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } } - public override bool CanConvert(Type objectType) + public override void Write(Utf8JsonWriter writer, TTLStatus value, JsonSerializerOptions options) { - return objectType == typeof(TTLStatus); + writer.WriteStringValue(value.Status); } } @@ -169,34 +163,34 @@ public AgentMember() /// public class AgentServiceRegistration { - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string ID { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Name { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string[] Tags { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public int Port { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Address { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool EnableTagOverride { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public AgentServiceCheck Check { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public AgentServiceCheck[] Checks { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public IDictionary Meta { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public IDictionary TaggedAddresses { get; set; } } @@ -205,7 +199,7 @@ public class AgentServiceRegistration /// public class AgentCheckRegistration : AgentServiceCheck { - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string ServiceID { get; set; } } @@ -214,66 +208,65 @@ public class AgentCheckRegistration : AgentServiceCheck /// public class AgentServiceCheck { - - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string ID { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Name { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Notes { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Script { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string[] Args { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string DockerContainerID { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Shell { get; set; } // Only supported for Docker. [JsonConverter(typeof(DurationTimespanConverter))] - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public TimeSpan? Interval { get; set; } [JsonConverter(typeof(DurationTimespanConverter))] - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public TimeSpan? Timeout { get; set; } [JsonConverter(typeof(DurationTimespanConverter))] - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public TimeSpan? TTL { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string HTTP { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public Dictionary> Header { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Method { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Body { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string TCP { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] [JsonConverter(typeof(HealthStatusConverter))] public HealthStatus Status { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool TLSSkipVerify { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string GRPC { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool GRPCUseTLS { get; set; } /// @@ -285,7 +278,7 @@ public class AgentServiceCheck /// automatically be deregistered. /// [JsonConverter(typeof(DurationTimespanConverter))] - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public TimeSpan? DeregisterCriticalServiceAfter { get; set; } } @@ -325,9 +318,9 @@ internal Agent(ConsulClient c) /// Self is used to query the agent we are speaking to for information about itself /// /// A somewhat dynamic object representing the various data elements in Self - public Task>>> Self(CancellationToken ct = default(CancellationToken)) + public Task>>> Self(CancellationToken ct = default(CancellationToken)) { - return _client.Get>>("/v1/agent/self").Execute(ct); + return _client.Get>>("/v1/agent/self").Execute(ct); } /// @@ -353,7 +346,7 @@ public string NodeName { if (_nodeName == null) { - _nodeName = (await Self(ct).ConfigureAwait(false)).Response["Config"]["NodeName"]; + _nodeName = (await Self(ct).ConfigureAwait(false)).Response["Config"]["NodeName"].GetString(); } } } diff --git a/Consul/AuthMethod.cs b/Consul/AuthMethod.cs index 122908256..d6709dc42 100644 --- a/Consul/AuthMethod.cs +++ b/Consul/AuthMethod.cs @@ -18,9 +18,9 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -31,9 +31,9 @@ public class AuthMethodEntry { public string Name { get; set; } public string Type { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Description { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public Dictionary Config { get; set; } public bool ShouldSerializeCreateIndex() @@ -79,9 +79,9 @@ internal AuthMethod(ConsulClient c) private class AuthMethodActionResult : AuthMethodEntry { - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ulong CreateIndex { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ulong ModifyIndex { get; set; } } diff --git a/Consul/Catalog.cs b/Consul/Catalog.cs index f47427bd6..e96ba4f82 100644 --- a/Consul/Catalog.cs +++ b/Consul/Catalog.cs @@ -18,9 +18,9 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -28,7 +28,7 @@ public class Node { // Cannot be "Node" as in the Go API because in C#, properties cannot // have the same name as their enclosing class. - [JsonProperty(PropertyName = "Node")] + [JsonPropertyName("Node")] public string Name { get; set; } public string Address { get; set; } public Dictionary TaggedAddresses { get; set; } diff --git a/Consul/Client.cs b/Consul/Client.cs index fd76ac99a..b9e5e3922 100644 --- a/Consul/Client.cs +++ b/Consul/Client.cs @@ -23,7 +23,10 @@ using System.Net.Http.Headers; using System.Security.Cryptography.X509Certificates; using Consul.Filtering; -using Newtonsoft.Json; +#if !(CORECLR || PORTABLE || PORTABLE40) +using System.Security.Permissions; +using System.Runtime.Serialization; +#endif namespace Consul { @@ -366,7 +369,6 @@ public void CheckDisposed() #endif public ConsulClientConfiguration Config { get { return _configContainer.Config; } } - #region New style config with Actions /// /// Initializes a new Consul client with a default configuration that connects to 127.0.0.1:8500. diff --git a/Consul/Client_DeleteRequests.cs b/Consul/Client_DeleteRequests.cs index 34b3e42db..819fcad70 100644 --- a/Consul/Client_DeleteRequests.cs +++ b/Consul/Client_DeleteRequests.cs @@ -76,9 +76,9 @@ public async Task> Execute(CancellationToken ct) } } - if (response.IsSuccessStatusCode) + if (response.IsSuccessStatusCode && response.Content.Headers.ContentLength.GetValueOrDefault(0) > 0) { - result.Response = Deserialize(ResponseStream); + result.Response = await Deserialize(ResponseStream).ConfigureAwait(false); } result.RequestTime = timer.Elapsed; diff --git a/Consul/Client_GetRequests.cs b/Consul/Client_GetRequests.cs index 50fe83687..0400f85a6 100644 --- a/Consul/Client_GetRequests.cs +++ b/Consul/Client_GetRequests.cs @@ -92,9 +92,9 @@ public async Task> Execute(CancellationToken ct) } } - if (response.IsSuccessStatusCode) + if (response.IsSuccessStatusCode && response.Content.Headers.ContentLength.GetValueOrDefault(0) > 0) { - result.Response = Deserialize(ResponseStream); + result.Response = await Deserialize(ResponseStream).ConfigureAwait(false); } result.RequestTime = timer.Elapsed; diff --git a/Consul/Client_PostRequests.cs b/Consul/Client_PostRequests.cs index f8a6a769c..ff89f1b2c 100644 --- a/Consul/Client_PostRequests.cs +++ b/Consul/Client_PostRequests.cs @@ -81,9 +81,9 @@ public async Task> Execute(CancellationToken ct) } } - if (response.IsSuccessStatusCode) + if (response.IsSuccessStatusCode && response.Content.Headers.ContentLength.GetValueOrDefault(0) > 0) { - result.Response = Deserialize(ResponseStream); + result.Response = await Deserialize(ResponseStream).ConfigureAwait(false); } result.RequestTime = timer.Elapsed; @@ -277,9 +277,9 @@ public async Task> Execute(CancellationToken ct) } } - if (response.IsSuccessStatusCode) + if (response.IsSuccessStatusCode && response.Content.Headers.ContentLength.GetValueOrDefault(0) > 0) { - result.Response = Deserialize(ResponseStream); + result.Response = await Deserialize(ResponseStream).ConfigureAwait(false); } result.RequestTime = timer.Elapsed; diff --git a/Consul/Client_PutRequests.cs b/Consul/Client_PutRequests.cs index 11cdd4daa..35e0c0f49 100644 --- a/Consul/Client_PutRequests.cs +++ b/Consul/Client_PutRequests.cs @@ -76,9 +76,9 @@ public async Task> Execute(CancellationToken ct) } } - if (response.IsSuccessStatusCode) + if (response.IsSuccessStatusCode && response.Content.Headers.ContentLength.GetValueOrDefault(0) > 0) { - result.Response = Deserialize(ResponseStream); + result.Response = await Deserialize(ResponseStream).ConfigureAwait(false); } result.RequestTime = timer.Elapsed; @@ -334,8 +334,8 @@ public async Task> Execute(CancellationToken ct) ResponseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); if (!response.IsSuccessStatusCode && ( - (response.StatusCode != HttpStatusCode.NotFound && typeof(TOut) != typeof(TxnResponse)) || - (response.StatusCode != HttpStatusCode.Conflict && typeof(TOut) == typeof(TxnResponse)))) + (response.StatusCode != HttpStatusCode.NotFound && typeof(TOut) != typeof(KVTxnResponse)) || + (response.StatusCode != HttpStatusCode.Conflict && typeof(TOut) == typeof(KVTxnResponse)))) { if (ResponseStream == null) { @@ -351,9 +351,9 @@ public async Task> Execute(CancellationToken ct) if (response.IsSuccessStatusCode || // Special case for KV txn operations - (response.StatusCode == HttpStatusCode.Conflict && typeof(TOut) == typeof(TxnResponse))) + (response.StatusCode == HttpStatusCode.Conflict && typeof(TOut) == typeof(KVTxnResponse))) { - result.Response = Deserialize(ResponseStream); + result.Response = await Deserialize(ResponseStream).ConfigureAwait(false); } result.RequestTime = timer.Elapsed; diff --git a/Consul/Client_Request.cs b/Consul/Client_Request.cs index 24723f819..e12f8c3cb 100644 --- a/Consul/Client_Request.cs +++ b/Consul/Client_Request.cs @@ -21,7 +21,9 @@ using System.Diagnostics; using System.IO; using System.Net.Http; -using Newtonsoft.Json; +using System.Text.Json; +using System.Threading.Tasks; + namespace Consul { @@ -55,8 +57,6 @@ public abstract class ConsulRequest internal Stream ResponseStream { get; set; } internal string Endpoint { get; set; } - internal readonly JsonSerializer _serializer = new JsonSerializer(); - internal ConsulRequest(ConsulClient client, string url, HttpMethod method) { Client = client; @@ -102,20 +102,14 @@ protected Uri BuildConsulUri(string url, Dictionary p) return builder.Uri; } - protected TOut Deserialize(Stream stream) + protected ValueTask Deserialize(Stream stream) { - using (var reader = new StreamReader(stream)) - { - using (var jsonReader = new JsonTextReader(reader)) - { - return _serializer.Deserialize(jsonReader); - } - } + return JsonSerializer.DeserializeAsync(stream); } protected byte[] Serialize(object value) { - return System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)); + return System.Text.Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value)); } } } diff --git a/Consul/Consul.csproj b/Consul/Consul.csproj index 6248e64af..4b35b4b0f 100644 --- a/Consul/Consul.csproj +++ b/Consul/Consul.csproj @@ -11,33 +11,19 @@ - - - - - - - - - - - $(ILRepack) /parallel /internalize /out:ILRepack/$(AssemblyName).dll - $(ILRepackCommand) /keyfile:$([System.IO.Path]::GetFullPath('$(AssemblyOriginatorKeyFile)')) - $(ILRepackCommand) $(AssemblyName).dll @(ArtifactsToMerge->'%(filename)%(extension)', ' ') - mono $(ILRepackCommand) - - - - - - - + + + + + + $(DefineConstants);CORECLR + diff --git a/Consul/Event.cs b/Consul/Event.cs index 86b26f736..c30e585f9 100644 --- a/Consul/Event.cs +++ b/Consul/Event.cs @@ -19,9 +19,10 @@ using System; using System.Globalization; using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -42,12 +43,6 @@ public class UserEvent public class Event : IEventEndpoint { - private class EventCreationResult - { - [JsonProperty] - internal string ID { get; set; } - } - private readonly ConsulClient _client; internal Event(ConsulClient c) @@ -68,7 +63,7 @@ internal Event(ConsulClient c) /// public async Task> Fire(UserEvent ue, WriteOptions q, CancellationToken ct = default(CancellationToken)) { - var req = _client.Put(string.Format("/v1/event/fire/{0}", ue.Name), ue.Payload, q); + var req = _client.Put(string.Format("/v1/event/fire/{0}", ue.Name), ue.Payload, q); if (!string.IsNullOrEmpty(ue.NodeFilter)) { req.Params["node"] = ue.NodeFilter; @@ -82,7 +77,7 @@ internal Event(ConsulClient c) req.Params["tag"] = ue.TagFilter; } var res = await req.Execute(ct).ConfigureAwait(false); - return new WriteResult(res, res.Response.ID); + return new WriteResult(res, res.Response.GetProperty("ID").GetString()); } /// diff --git a/Consul/Health.cs b/Consul/Health.cs index cebcc39bd..44fe511a6 100644 --- a/Consul/Health.cs +++ b/Consul/Health.cs @@ -18,10 +18,11 @@ using System; using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using Consul.Filtering; -using Newtonsoft.Json; namespace Consul { @@ -64,18 +65,16 @@ public override int GetHashCode() } } - public class HealthStatusConverter : JsonConverter + public class HealthStatusConverter : JsonConverter { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override bool CanConvert(Type objectType) { - serializer.Serialize(writer, ((HealthStatus)value).Status); + return objectType == typeof(HealthStatus); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) + public override HealthStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var status = (string)serializer.Deserialize(reader, typeof(string)); - switch (status) + switch (reader.GetString()) { case "passing": return HealthStatus.Passing; @@ -88,13 +87,9 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } } - public override bool CanConvert(Type objectType) + public override void Write(Utf8JsonWriter writer, HealthStatus value, JsonSerializerOptions options) { - if (objectType == typeof(HealthStatus)) - { - return true; - } - return false; + writer.WriteStringValue(value.Status); } } diff --git a/Consul/Interfaces/IAgentEndpoint.cs b/Consul/Interfaces/IAgentEndpoint.cs index ca3687b26..85837411d 100644 --- a/Consul/Interfaces/IAgentEndpoint.cs +++ b/Consul/Interfaces/IAgentEndpoint.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Consul.Filtering; @@ -45,7 +46,7 @@ public interface IAgentEndpoint string NodeName { get; } Task GetNodeName(CancellationToken ct = default(CancellationToken)); Task PassTTL(string checkID, string note, CancellationToken ct = default(CancellationToken)); - Task>>> Self(CancellationToken ct = default(CancellationToken)); + Task>>> Self(CancellationToken ct = default(CancellationToken)); Task ServiceDeregister(string serviceID, CancellationToken ct = default(CancellationToken)); Task ServiceRegister(AgentServiceRegistration service, CancellationToken ct = default(CancellationToken)); Task ServiceRegister(AgentServiceRegistration service, bool replaceExistingChecks, CancellationToken ct = default(CancellationToken)); diff --git a/Consul/KV.cs b/Consul/KV.cs index dcea701f9..39fd97c61 100644 --- a/Consul/KV.cs +++ b/Consul/KV.cs @@ -20,9 +20,10 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -102,18 +103,16 @@ public override int GetHashCode() } } - public class KVTxnVerbTypeConverter : JsonConverter + public class KVTxnVerbTypeConverter : JsonConverter { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override bool CanConvert(Type objectType) { - serializer.Serialize(writer, ((KVTxnVerb)value).Operation); + return objectType == typeof(KVTxnVerb); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) + public override KVTxnVerb Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var status = (string)serializer.Deserialize(reader, typeof(string)); - switch (status) + switch (reader.GetString()) { case "set": return KVTxnVerb.Set; @@ -142,9 +141,9 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } } - public override bool CanConvert(Type objectType) + public override void Write(Utf8JsonWriter writer, KVTxnVerb value, JsonSerializerOptions options) { - return objectType == typeof(KVTxnVerb); + writer.WriteStringValue(value.Operation); } } @@ -169,13 +168,14 @@ public KVTxnOp(string key, KVTxnVerb verb) /// /// KVTxnResponse is used to return the results of a transaction. /// + [JsonConverter(typeof(TxnResponseConverter))] public class KVTxnResponse { [JsonIgnore] public bool Success { get; internal set; } - [JsonProperty] + [JsonInclude] public List Errors { get; internal set; } - [JsonProperty] + [JsonInclude] public List Results { get; internal set; } public KVTxnResponse() @@ -183,38 +183,6 @@ public KVTxnResponse() Results = new List(); Errors = new List(); } - - internal KVTxnResponse(TxnResponse txnRes) - { - if (txnRes == null) - { - Results = new List(0); - Errors = new List(0); - return; - } - - if (txnRes.Results == null) - { - Results = new List(0); - } - else - { - Results = new List(txnRes.Results.Count); - foreach (var txnResult in txnRes.Results) - { - Results.Add(txnResult.KV); - } - } - - if (txnRes.Errors == null) - { - Errors = new List(0); - } - else - { - Errors = txnRes.Errors; - } - } } /// @@ -599,10 +567,10 @@ public KV(ConsulClient c) txnOps.Add(new TxnOp() { KV = kvTxnOp }); } - var req = _client.Put, TxnResponse>("/v1/txn", txnOps, q); + var req = _client.Put, KVTxnResponse>("/v1/txn", txnOps, q); var txnRes = await req.Execute(ct).ConfigureAwait(false); - var res = new WriteResult(txnRes, new KVTxnResponse(txnRes.Response)); + var res = new WriteResult(txnRes, txnRes.Response); res.Response.Success = txnRes.StatusCode == System.Net.HttpStatusCode.OK; diff --git a/Consul/Operator.cs b/Consul/Operator.cs index dad101f30..bd850517e 100644 --- a/Consul/Operator.cs +++ b/Consul/Operator.cs @@ -19,9 +19,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -114,15 +114,6 @@ internal Operator(ConsulClient c) _client = c; } - /// - /// KeyringRequest is used for performing Keyring operations - /// - private class KeyringRequest - { - [JsonProperty] - internal string Key { get; set; } - } - /// /// RaftGetConfiguration is used to query the current Raft peer set. /// @@ -179,7 +170,7 @@ private class KeyringRequest /// public Task KeyringInstall(string key, WriteOptions q, CancellationToken ct = default(CancellationToken)) { - return _client.Post("/v1/operator/keyring", new KeyringRequest() { Key = key }, q).Execute(ct); + return _client.Post("/v1/operator/keyring", new { Key = key }, q).Execute(ct); } /// @@ -211,7 +202,7 @@ private class KeyringRequest /// public Task KeyringRemove(string key, WriteOptions q, CancellationToken ct = default(CancellationToken)) { - return _client.DeleteAccepting("/v1/operator/keyring", new KeyringRequest() { Key = key }, q).Execute(ct); + return _client.DeleteAccepting("/v1/operator/keyring", new { Key = key }, q).Execute(ct); } /// @@ -227,7 +218,7 @@ private class KeyringRequest /// public Task KeyringUse(string key, WriteOptions q, CancellationToken ct = default(CancellationToken)) { - return _client.Put("/v1/operator/keyring", new KeyringRequest() { Key = key }, q).Execute(ct); + return _client.Put("/v1/operator/keyring", new { Key = key }, q).Execute(ct); } } diff --git a/Consul/Policy.cs b/Consul/Policy.cs index 5a2b8c03c..635994c62 100644 --- a/Consul/Policy.cs +++ b/Consul/Policy.cs @@ -17,9 +17,9 @@ // ----------------------------------------------------------------------- using System; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -54,7 +54,7 @@ public class PolicyEntry public string Name { get; set; } public string Description { get; set; } public string Rules { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string[] Datacenters { get; set; } public bool ShouldSerializeCreateIndex() diff --git a/Consul/PreparedQuery.cs b/Consul/PreparedQuery.cs index 1ebc5b519..d482d8d12 100644 --- a/Consul/PreparedQuery.cs +++ b/Consul/PreparedQuery.cs @@ -20,9 +20,10 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -41,7 +42,7 @@ public class QueryDatacenterOptions /// never try a datacenter multiple times, so those are subtracted from /// this list before proceeding. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public List Datacenters { get; set; } public QueryDatacenterOptions() @@ -58,7 +59,8 @@ public class QueryDNSOptions /// /// TTL is the time to live for the served DNS results. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + [JsonConverter(typeof(DurationTimespanConverter))] public TimeSpan? TTL { get; set; } } @@ -70,7 +72,7 @@ public class ServiceQuery /// /// Service is the service to query. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Service { get; set; } /// @@ -78,13 +80,13 @@ public class ServiceQuery /// sort from. The magic "_agent" value is supported, which sorts near /// the agent which initiated the request by default. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Near { get; set; } /// /// Failover controls what we do if there are no healthy nodes in the local datacenter. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public QueryDatacenterOptions Failover { get; set; } /// @@ -92,7 +94,7 @@ public class ServiceQuery /// health checks (critical AND warning checks will cause a node to be /// discarded) /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool OnlyPassing { get; set; } /// @@ -100,7 +102,7 @@ public class ServiceQuery /// this list it must be present. If the tag is preceded with "!" then /// it is disallowed. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public List Tags { get; set; } } @@ -113,14 +115,14 @@ public class QueryTemplate /// Type specifies the type of the query template. Currently only /// "name_prefix_match" is supported. This field is required. /// - [JsonProperty(NullValueHandling = NullValueHandling.Include)] + [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public string Type { get; set; } /// /// Regexp allows specifying a regex pattern to match against the name /// of the query being executed. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Regexp { get; set; } public QueryTemplate() @@ -151,7 +153,7 @@ public class PreparedQueryDefinition /// Session is an optional session to tie this query's lifetime to. If /// this is omitted then the query will not expire. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Session { get; set; } /// @@ -159,24 +161,24 @@ public class PreparedQueryDefinition /// used when a query is subsequently executed. This token, or a token /// with management privileges, must be used to change the query later. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Token { get; set; } /// /// Service defines a service query (leaving things open for other types /// later). /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ServiceQuery Service { get; set; } /// /// DNS has options that control how the results of this query are /// served over DNS. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public QueryDNSOptions DNS { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public QueryTemplate Template { get; set; } } @@ -214,11 +216,6 @@ public class PreparedQueryExecuteResponse public class PreparedQuery : IPreparedQueryEndpoint { - private class PreparedQueryCreationResult - { - [JsonProperty] - internal string ID { get; set; } - } private readonly ConsulClient _client; internal PreparedQuery(ConsulClient c) @@ -233,8 +230,8 @@ internal PreparedQuery(ConsulClient c) public async Task> Create(PreparedQueryDefinition query, WriteOptions q, CancellationToken ct = default(CancellationToken)) { - var res = await _client.Post("/v1/query", query, q).Execute(ct).ConfigureAwait(false); - return new WriteResult(res, res.Response.ID); + var res = await _client.Post("/v1/query", query, q).Execute(ct).ConfigureAwait(false); + return new WriteResult(res, res.Response.GetProperty("ID").GetString()); } public Task Delete(string queryID, CancellationToken ct = default(CancellationToken)) diff --git a/Consul/Role.cs b/Consul/Role.cs index e4023b19f..a9d957dc1 100644 --- a/Consul/Role.cs +++ b/Consul/Role.cs @@ -17,9 +17,9 @@ // ----------------------------------------------------------------------- using System; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -53,9 +53,9 @@ public class RoleEntry public string ID { get; set; } public string Name { get; set; } public string Description { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public PolicyLink[] Policies { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ServiceIdentity[] ServiceIdentities { get; set; } public bool ShouldSerializeCreateIndex() diff --git a/Consul/Semaphore.cs b/Consul/Semaphore.cs index 378e941c2..673e7b137 100644 --- a/Consul/Semaphore.cs +++ b/Consul/Semaphore.cs @@ -21,9 +21,11 @@ using System.Diagnostics; using System.Linq; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; + #if !(NETSTANDARD || NETCOREAPP) using System.Security.Permissions; using System.Runtime.Serialization; @@ -202,7 +204,6 @@ private class SemaphoreLock { private int _limit; - [JsonProperty] internal int Limit { get { return _limit; } @@ -219,13 +220,27 @@ internal int Limit } } - [JsonProperty] internal Dictionary Holders { get; set; } internal SemaphoreLock() { Holders = new Dictionary(); } + + internal SemaphoreLock(JsonDocument json) + { + Limit = json.RootElement.GetProperty("Limit").GetInt32(); + Holders = new Dictionary(); + foreach (var holder in json.RootElement.GetProperty("Holders").EnumerateObject()) + { + Holders.Add(holder.Name, holder.Value.GetBoolean()); + } + } + + internal string ToJson() + { + return JsonSerializer.Serialize(new { Limit, Holders }); + } } /// @@ -710,7 +725,10 @@ private SemaphoreLock DecodeLock(KVPair pair) return new SemaphoreLock() { Limit = Opts.Limit }; } - return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(pair.Value)); + using (var holderJson = JsonDocument.Parse(Encoding.UTF8.GetString(pair.Value))) + { + return new SemaphoreLock(holderJson); + } } /// @@ -721,7 +739,7 @@ private SemaphoreLock DecodeLock(KVPair pair) /// A K/V pair with the lock data encoded in the Value field private KVPair EncodeLock(SemaphoreLock l, ulong oldIndex) { - var jsonValue = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(l)); + var jsonValue = Encoding.UTF8.GetBytes(l.ToJson()); return new KVPair(string.Join("/", Opts.Prefix, DefaultSemaphoreKey)) { diff --git a/Consul/Session.cs b/Consul/Session.cs index 99b5e313c..e23a3a93d 100644 --- a/Consul/Session.cs +++ b/Consul/Session.cs @@ -21,9 +21,10 @@ using System.Diagnostics; using System.Net; using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -54,18 +55,11 @@ public override int GetHashCode() } } - public class SessionBehaviorConverter : JsonConverter + public class SessionBehaviorConverter : JsonConverter { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override SessionBehavior Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - serializer.Serialize(writer, ((SessionBehavior)value).Behavior); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) - { - var behavior = (string)serializer.Deserialize(reader, typeof(string)); - switch (behavior) + switch (reader.GetString()) { case "release": return SessionBehavior.Release; @@ -76,9 +70,9 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } } - public override bool CanConvert(Type objectType) + public override void Write(Utf8JsonWriter writer, SessionBehavior value, JsonSerializerOptions options) { - return objectType == typeof(SessionBehavior); + writer.WriteStringValue(value.Behavior); } } @@ -119,24 +113,24 @@ public class SessionEntry public string ID { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Name { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Node { get; set; } public List Checks { get; set; } [JsonConverter(typeof(NanoSecTimespanConverter))] - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public TimeSpan? LockDelay { get; set; } [JsonConverter(typeof(SessionBehaviorConverter))] - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public SessionBehavior Behavior { get; set; } [JsonConverter(typeof(DurationTimespanConverter))] - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public TimeSpan? TTL { get; set; } public SessionEntry() @@ -165,12 +159,6 @@ public bool ShouldSerializeChecks() /// public class Session : ISessionEndpoint { - private class SessionCreationResult - { - [JsonProperty] - internal string ID { get; set; } - } - private readonly ConsulClient _client; internal Session(ConsulClient c) @@ -283,8 +271,8 @@ public Task RenewPeriodic(TimeSpan initialTTL, string id, WriteOptions q, Cancel /// A write result containing the new session ID public async Task> Create(SessionEntry se, WriteOptions q, CancellationToken ct = default(CancellationToken)) { - var res = await _client.Put("/v1/session/create", se, q).Execute(ct).ConfigureAwait(false); - return new WriteResult(res, res.Response.ID); + var res = await _client.Put("/v1/session/create", se, q).Execute(ct).ConfigureAwait(false); + return new WriteResult(res, res.Response.GetProperty("ID").GetString()); } /// /// CreateNoChecks is like Create but is used specifically to create a session with no associated health checks. diff --git a/Consul/Token.cs b/Consul/Token.cs index 71743e02f..c1d2897d6 100644 --- a/Consul/Token.cs +++ b/Consul/Token.cs @@ -18,9 +18,9 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -29,19 +29,19 @@ namespace Consul /// public class TokenEntry { - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string AccessorID { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string SecretID { get; set; } public string Description { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public PolicyLink[] Policies { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public RoleLink[] Roles { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ServiceIdentity[] ServiceIdentities { get; set; } public bool Local { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string AuthMethod { get; set; } @@ -104,13 +104,13 @@ internal Token(ConsulClient c) private class TokenActionResult : TokenEntry { - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public DateTime? CreateTime { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Hash { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ulong CreateIndex { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ulong ModifyIndex { get; set; } } diff --git a/Consul/Transaction.cs b/Consul/Transaction.cs index 72f436516..1f83008e7 100644 --- a/Consul/Transaction.cs +++ b/Consul/Transaction.cs @@ -19,8 +19,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Consul { @@ -36,17 +37,59 @@ internal class TxnResult public class TxnError { - [JsonProperty] + [JsonInclude] public int OpIndex { get; private set; } - [JsonProperty] + [JsonInclude] public string What { get; private set; } } - internal class TxnResponse + public class TxnResponseConverter : JsonConverter { - [JsonProperty] - internal List Results { get; set; } - [JsonProperty] - internal List Errors { get; set; } + public override KVTxnResponse Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var result = new KVTxnResponse() { Results = new List() }; + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.PropertyName + && reader.GetString() == "Results" + && reader.Read() + && reader.TokenType == JsonTokenType.StartArray) + { + while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) + { + if (reader.TokenType == JsonTokenType.StartObject || reader.TokenType == JsonTokenType.EndObject) + { + continue; + } + + if (reader.TokenType == JsonTokenType.PropertyName && reader.Read()) + { + var resultPair = JsonSerializer.Deserialize(ref reader, options); + result.Results.Add(resultPair); + } + } + } + + if (reader.TokenType == JsonTokenType.PropertyName + && reader.GetString() == "Errors" + && reader.Read() + && reader.TokenType == JsonTokenType.StartArray) + { + result.Errors = JsonSerializer.Deserialize>(ref reader, options); + } + } + + if (result.Errors == null) + { + result.Errors = new List(0); + } + return result; + } + + public override void Write(Utf8JsonWriter writer, KVTxnResponse value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } } } diff --git a/Consul/Utilities/JsonConverters.cs b/Consul/Utilities/JsonConverters.cs index 9bd3760ac..af7503a06 100644 --- a/Consul/Utilities/JsonConverters.cs +++ b/Consul/Utilities/JsonConverters.cs @@ -20,126 +20,139 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using Newtonsoft.Json; +using System.Text.Json; +using System.Text.Json.Serialization; namespace Consul { - public class NanoSecTimespanConverter : JsonConverter + public class NanoSecTimespanConverter : JsonConverter { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override TimeSpan? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - serializer.Serialize(writer, (long)((TimeSpan)value).TotalMilliseconds * 1000000, typeof(long)); - } + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) - { - return Extensions.FromGoDuration((string)serializer.Deserialize(reader, typeof(string))); + if (reader.TokenType == JsonTokenType.Number) + { + if (reader.TryGetUInt64(out var result)) + { + return TimeSpan.FromTicks((long)(result / 100)); + } + } + return Extensions.FromGoDuration(reader.GetString()); } - public override bool CanConvert(Type objectType) + public override void Write(Utf8JsonWriter writer, TimeSpan? value, JsonSerializerOptions options) { - if (objectType == typeof(TimeSpan)) + if (value.HasValue) + { + writer.WriteNumberValue((long)value.Value.TotalMilliseconds * 1000000); + } + else { - return true; + writer.WriteNullValue(); } - return false; } } - public class DurationTimespanConverter : JsonConverter + public class DurationTimespanConverter : JsonConverter { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override TimeSpan? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - serializer.Serialize(writer, ((TimeSpan)value).ToGoDuration()); - } + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) - { - return Extensions.FromGoDuration((string)serializer.Deserialize(reader, typeof(string))); + if (reader.TokenType == JsonTokenType.Number) + { + if (reader.TryGetUInt64(out var result)) + { + return TimeSpan.FromTicks((long)(result / 100)); + } + } + return Extensions.FromGoDuration(reader.GetString()); } - public override bool CanConvert(Type objectType) + public override void Write(Utf8JsonWriter writer, TimeSpan? value, JsonSerializerOptions options) { - if (objectType == typeof(TimeSpan)) + if (value.HasValue) { - return true; + writer.WriteStringValue(value.Value.ToGoDuration()); + } + else + { + writer.WriteNullValue(); } - return false; } } - public class KVPairConverter : JsonConverter + public class KVPairConverter : JsonConverter { static readonly Lazy ObjProps = new Lazy(() => typeof(KVPair).GetRuntimeProperties().Select(p => p.Name).ToArray()); - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + + public override bool CanConvert(Type objectType) { - throw new NotImplementedException(); + return objectType == typeof(KVPair); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) + public override KVPair Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { KVPair result = new KVPair(); while (reader.Read()) { - if (reader.TokenType == JsonToken.StartObject) { continue; } - if (reader.TokenType == JsonToken.EndObject) { return result; } - if (reader.TokenType == JsonToken.PropertyName) + if (reader.TokenType == JsonTokenType.StartObject) { continue; } + if (reader.TokenType == JsonTokenType.EndObject) { return result; } + if (reader.TokenType == JsonTokenType.PropertyName) { - string jsonPropName = reader.Value.ToString(); + string jsonPropName = reader.GetString(); + if (jsonPropName == null) + { + continue; + } + var propName = ObjProps.Value.FirstOrDefault(p => p.Equals(jsonPropName, StringComparison.OrdinalIgnoreCase)); if (propName != null) { PropertyInfo pi = result.GetType().GetRuntimeProperty(propName); - if (jsonPropName.Equals("Flags", StringComparison.OrdinalIgnoreCase)) + if (jsonPropName.Equals("Flags", StringComparison.OrdinalIgnoreCase) && reader.Read()) { - if (!string.IsNullOrEmpty(reader.ReadAsString())) - { - var val = Convert.ToUInt64(reader.Value); - pi.SetValue(result, val, null); - } + pi.SetValue(result, reader.GetUInt64(), null); } - else if (jsonPropName.Equals("Value", StringComparison.OrdinalIgnoreCase)) + else if (jsonPropName.Equals("Value", StringComparison.OrdinalIgnoreCase) && reader.Read()) { - if (!string.IsNullOrEmpty(reader.ReadAsString())) + if (reader.TokenType == JsonTokenType.Null) { - var val = Convert.FromBase64String(reader.Value.ToString()); - pi.SetValue(result, val, null); + continue; } + pi.SetValue(result, reader.GetBytesFromBase64(), null); } - else + else if (reader.Read()) { - if (reader.Read()) - { - var convertedValue = Convert.ChangeType(reader.Value, pi.PropertyType); - pi.SetValue(result, convertedValue, null); - } + pi.SetValue(result, JsonSerializer.Deserialize(ref reader, pi.PropertyType, options), null); } } } } - return result; - } - public override bool CanConvert(Type objectType) - { - if (objectType == typeof(KVPair)) - { - return true; - } - return false; + return result; } - public override bool CanWrite + public override void Write(Utf8JsonWriter writer, KVPair value, JsonSerializerOptions options) { - get - { - return false; - } + writer.WriteStartObject(); + writer.WriteString("Key", value.Key); + writer.WriteNumber("CreateIndex", value.CreateIndex); + writer.WriteNumber("ModifyIndex", value.ModifyIndex); + writer.WriteNumber("LockIndex", value.LockIndex); + writer.WriteNumber("Flags", value.Flags); + writer.WriteBase64String("Session", value.Value); + writer.WriteString("Session", value.Session); + writer.WriteEndObject(); } } }