From d75f8a32c604636247f7a45dd3276fe00a45b64b Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Tue, 10 Dec 2024 14:50:42 +0530 Subject: [PATCH 1/6] refactor: Updating to system.text.json --- .talismanrc | 2 +- .../Configuration/LivePreviewConfig.cs | 6 +- Contentstack.Core/Contentstack.Core.csproj | 3 +- Contentstack.Core/ContentstackClient.cs | 67 +++++++++--------- .../Internals/AssetJsonConverter.cs | 24 +++---- .../Internals/ContentStackError.cs | 12 ++-- .../Internals/ContentstackConvert.cs | 6 +- .../Internals/HttpRequestHandler.cs | 34 +++++----- .../JsonSerializerOptionsConverters.cs | 68 +++++++++++++++++++ Contentstack.Core/Internals/StackOutput.cs | 5 +- Contentstack.Core/Models/Asset.cs | 59 ++++++++-------- Contentstack.Core/Models/AssetLibrary.cs | 37 +++++----- Contentstack.Core/Models/ContentType.cs | 37 +++++----- .../Models/ContentstackCollection.cs | 10 +-- 14 files changed, 210 insertions(+), 160 deletions(-) create mode 100644 Contentstack.Core/Internals/JsonSerializerOptionsConverters.cs mode change 100755 => 100644 Contentstack.Core/Models/ContentstackCollection.cs diff --git a/.talismanrc b/.talismanrc index 2fd7ede5..51046293 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,6 +1,6 @@ fileignoreconfig: - filename: Contentstack.Core/Internals/HttpRequestHandler.cs - checksum: 93c1659f3bc7527956f0fd12db46441297fac3a4366d273bcbb3425d2351300e + checksum: 29bb8548d65cdc5800fc939e526797bb3515f528d8082a58a0c9c6215dec1651 - filename: Contentstack.Core/Models/Entry.cs checksum: 79320b005882981fd7c79fe73832f28284db686927942e46b422ac9e88405023 - filename: Contentstack.Core/ContentstackClient.cs diff --git a/Contentstack.Core/Configuration/LivePreviewConfig.cs b/Contentstack.Core/Configuration/LivePreviewConfig.cs index 240db8e1..0fbecdf9 100644 --- a/Contentstack.Core/Configuration/LivePreviewConfig.cs +++ b/Contentstack.Core/Configuration/LivePreviewConfig.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections; -using Newtonsoft.Json.Linq; +using System.Text.Json; namespace Contentstack.Core.Configuration { @@ -13,6 +11,6 @@ public class LivePreviewConfig internal string LivePreview { get; set; } internal string ContentTypeUID { get; set; } internal string EntryUID { get; set; } - internal JObject PreviewResponse { get; set; } + internal JsonElement PreviewResponse { get; set; } } } diff --git a/Contentstack.Core/Contentstack.Core.csproj b/Contentstack.Core/Contentstack.Core.csproj index 030a3a79..4d4bb79c 100644 --- a/Contentstack.Core/Contentstack.Core.csproj +++ b/Contentstack.Core/Contentstack.Core.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net47;net472; + net7.0 contentstack.csharp Contentstack .NET SDK for the Contentstack Content Delivery API. @@ -28,7 +28,6 @@ - diff --git a/Contentstack.Core/ContentstackClient.cs b/Contentstack.Core/ContentstackClient.cs index 87346816..0af89370 100644 --- a/Contentstack.Core/ContentstackClient.cs +++ b/Contentstack.Core/ContentstackClient.cs @@ -1,18 +1,17 @@ using System; +using System.Collections; using System.Collections.Generic; -using Contentstack.Core.Internals; -using Contentstack.Core.Configuration; -using Microsoft.Extensions.Options; -using Contentstack.Core.Models; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json; +using System.IO; using System.Linq; -using System.Threading.Tasks; using System.Net; -using System.IO; -using System.Collections; -using Contentstack.Utils; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using Contentstack.Core.Configuration; using Contentstack.Core.Interfaces; +using Contentstack.Core.Internals; +using Contentstack.Core.Models; +using Microsoft.Extensions.Options; namespace Contentstack.Core { @@ -24,7 +23,16 @@ public class ContentstackClient /// /// Gets or sets the settings that should be used for deserialization. /// - public JsonSerializerSettings SerializerSettings { get; set; } = new JsonSerializerSettings(); + public JsonSerializerOptions SerializerSettings { get; set; } = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + Converters = { + new JsonStringEnumConverter(), + new CustomUtcDateTimeConverter(), + new CustomNullableUtcDateTimeConverter(), + } + }; #region Internal Variables @@ -35,7 +43,6 @@ internal string StackApiKey } private ContentstackOptions _options; - internal JsonSerializer Serializer => JsonSerializer.Create(SerializerSettings); internal string _SyncUrl { get @@ -133,10 +140,6 @@ public ContentstackClient(IOptions options) throw new InvalidOperationException("Add PreviewToken or ManagementToken in LivePreviewConfig"); } } - this.SerializerSettings.DateParseHandling = DateParseHandling.None; - this.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat; - this.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; - this.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; foreach (Type t in CSJsonConverterAttribute.GetCustomAttribute(typeof(CSJsonConverterAttribute))) { @@ -209,22 +212,18 @@ internal static ContentstackException GetContentstackError(Exception ex) using (var reader = new StreamReader(stream)) { errorMessage = reader.ReadToEnd(); - JObject data = JObject.Parse(errorMessage.Replace("\r\n", "")); + var data = JsonSerializer.Deserialize(errorMessage); - JToken token = data["error_code"]; - if (token != null) - errorCode = token.Value(); + if (data.TryGetProperty("error_code", out var token)) + errorCode = token.GetInt32(); - token = data["error_message"]; - if (token != null) - errorMessage = token.Value(); + if (data.TryGetProperty("error_message", out token)) + errorMessage = token.GetString(); - token = data["errors"]; - if (token != null) - errors = token.ToObject>(); + if (data.TryGetProperty("errors", out token)) + errors = JsonSerializer.Deserialize>(token.GetRawText()); - var response = exResp as HttpWebResponse; - if (response != null) + if (exResp is HttpWebResponse response) statusCode = response.StatusCode; } } @@ -326,8 +325,8 @@ public async Task GetContentTypes(Dictionary param = null { HttpRequestHandler RequestHandler = new HttpRequestHandler(this); var outputResult = await RequestHandler.ProcessRequest(_Url, headers, mainJson, Branch: this.Config.Branch, timeout: this.Config.Timeout, proxy: this.Config.Proxy); - JObject data = JsonConvert.DeserializeObject(outputResult.Replace("\r\n", ""), this.SerializerSettings); - IList contentTypes = (IList)data["content_types"]; + var data = JsonSerializer.Deserialize(outputResult); + var contentTypes = data.GetProperty("content_types").EnumerateArray().ToList(); return contentTypes; } catch (Exception ex) @@ -336,7 +335,7 @@ public async Task GetContentTypes(Dictionary param = null } } - private async Task GetLivePreviewData() + private async Task GetLivePreviewData() { Dictionary headerAll = new Dictionary(); @@ -368,8 +367,8 @@ private async Task GetLivePreviewData() { HttpRequestHandler RequestHandler = new HttpRequestHandler(this); var outputResult = await RequestHandler.ProcessRequest(String.Format("{0}/content_types/{1}/entries/{2}", this.Config.getLivePreviewUrl(this.LivePreviewConfig), this.LivePreviewConfig.ContentTypeUID, this.LivePreviewConfig.EntryUID), headerAll, mainJson, Branch: this.Config.Branch, isLivePreview: true, timeout: this.Config.Timeout, proxy: this.Config.Proxy); - JObject data = JsonConvert.DeserializeObject(outputResult.Replace("\r\n", ""), this.SerializerSettings); - return (JObject)data["entry"]; + var data = JsonSerializer.Deserialize(outputResult); + return data.GetProperty("entry"); } catch (Exception ex) { @@ -784,7 +783,7 @@ private async Task GetResultAsync(string Init = "false", SyncType Syn { HttpRequestHandler requestHandler = new HttpRequestHandler(this); string js = await requestHandler.ProcessRequest(_SyncUrl, _LocalHeaders, mainJson, Branch: this.Config.Branch, timeout: this.Config.Timeout, proxy: this.Config.Proxy); - SyncStack stackSyncOutput = JsonConvert.DeserializeObject(js); + SyncStack stackSyncOutput = JsonSerializer.Deserialize(js); return stackSyncOutput; } catch (Exception ex) diff --git a/Contentstack.Core/Internals/AssetJsonConverter.cs b/Contentstack.Core/Internals/AssetJsonConverter.cs index 9fc72150..96e581bd 100644 --- a/Contentstack.Core/Internals/AssetJsonConverter.cs +++ b/Contentstack.Core/Internals/AssetJsonConverter.cs @@ -1,27 +1,27 @@ using System; -using Contentstack.Core; +using System.Text.Json; +using System.Text.Json.Serialization; using Contentstack.Core.Models; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Contentstack.Core.Internals { [CSJsonConverter("AssetJsonConverter")] public class AssetJsonConverter : JsonConverter { - public override Asset ReadJson(JsonReader reader, Type objectType, Asset existingValue, bool hasExistingValue, JsonSerializer serializer) + public override Asset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - JObject jObject = JObject.Load(reader); - JsonSerializerSettings SerializerSettings = new JsonSerializerSettings(); - JsonSerializer Serializer = JsonSerializer.Create(SerializerSettings); - Asset asset = jObject.ToObject(Serializer); - asset.ParseObject(jObject); - return asset; + using (JsonDocument document = JsonDocument.ParseValue(ref reader)) + { + JsonElement root = document.RootElement; + Asset asset = JsonSerializer.Deserialize(root.GetRawText(), options); + asset.ParseObject(root); + return asset; + } } - public override void WriteJson(JsonWriter writer, Asset value, JsonSerializer serializer) + public override void Write(Utf8JsonWriter writer, Asset value, JsonSerializerOptions options) { throw new NotImplementedException(); } } -} +} \ No newline at end of file diff --git a/Contentstack.Core/Internals/ContentStackError.cs b/Contentstack.Core/Internals/ContentStackError.cs index cb37a803..52f9b564 100644 --- a/Contentstack.Core/Internals/ContentStackError.cs +++ b/Contentstack.Core/Internals/ContentStackError.cs @@ -1,8 +1,8 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; using System.Net; - +using System.Text.Json.Serialization; + namespace Contentstack.Core.Internals { /// @@ -33,7 +33,7 @@ public class ContentstackException : Exception /// /// This is error message. /// - [JsonProperty("error_message")] + [JsonPropertyName("error_message")] public string ErrorMessage { get @@ -50,13 +50,13 @@ public string ErrorMessage /// /// This is error code. /// - [JsonProperty("error_code")] + [JsonPropertyName("error_code")] public int ErrorCode { get; set; } /// /// Set of errors in detail. /// - [JsonProperty("errors")] + [JsonPropertyName("errors")] public Dictionary Errors { get; set; } #endregion diff --git a/Contentstack.Core/Internals/ContentstackConvert.cs b/Contentstack.Core/Internals/ContentstackConvert.cs index b2d4d742..a35a2357 100644 --- a/Contentstack.Core/Internals/ContentstackConvert.cs +++ b/Contentstack.Core/Internals/ContentstackConvert.cs @@ -1,9 +1,5 @@ -using Newtonsoft.Json; -using System; +using System; using System.IO; -using System.Net.NetworkInformation; -using System.Security.Cryptography; -using System.Text; using System.Text.RegularExpressions; namespace Contentstack.Core.Internals diff --git a/Contentstack.Core/Internals/HttpRequestHandler.cs b/Contentstack.Core/Internals/HttpRequestHandler.cs index c6eff089..ed5ff715 100644 --- a/Contentstack.Core/Internals/HttpRequestHandler.cs +++ b/Contentstack.Core/Internals/HttpRequestHandler.cs @@ -4,9 +4,9 @@ using System.Linq; using System.Net; using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Contentstack.Core.Internals { @@ -35,7 +35,7 @@ public async Task ProcessRequest(string Url, Dictionary return value; } else if (kvp.Value is Dictionary) - value = JsonConvert.SerializeObject(kvp.Value); + value = JsonSerializer.Serialize(kvp.Value); else return String.Format("{0}={1}", kvp.Key, kvp.Value); @@ -75,7 +75,7 @@ public async Task ProcessRequest(string Url, Dictionary request = await plugin.OnRequest(client, request); }; - var serializedresult = JsonConvert.SerializeObject(BodyJson); + var serializedresult = JsonSerializer.Serialize(BodyJson); byte[] requestBody = Encoding.UTF8.GetBytes(serializedresult); StreamReader reader = null; HttpWebResponse response = null; @@ -108,42 +108,42 @@ public async Task ProcessRequest(string Url, Dictionary } - internal void updateLivePreviewContent(JObject response) + internal void updateLivePreviewContent(JsonObject response) { if (response.ContainsKey("uid") && response["uid"].ToString() == this.client.LivePreviewConfig.EntryUID) { - response.Merge(this.client.LivePreviewConfig.PreviewResponse, new JsonMergeSettings() + foreach (var property in this.client.LivePreviewConfig.PreviewResponse.AsObject()) { - MergeArrayHandling = MergeArrayHandling.Replace - }); + response[property.Key] = property.Value; + } } else { foreach (var content in response) { - if (content.Value.Type == JTokenType.Array) + if (content.Value is JsonArray) { - updateArray((JArray)response[content.Key]); + updateArray((JsonArray)response[content.Key]); } - else if (content.Value.Type == JTokenType.Object) + else if (content.Value is JsonObject) { - updateLivePreviewContent((JObject)response[content.Key]); + updateLivePreviewContent((JsonObject)response[content.Key]); } } } } - internal void updateArray(JArray array) + internal void updateArray(JsonArray array) { for (var i = 0; i < array.Count(); i++) { - if (array[i].Type == JTokenType.Array) + if (array[i] is JsonArray) { - updateArray((JArray)array[i]); + updateArray((JsonArray)array[i]); } - else if (array[i].Type == JTokenType.Object) + else if (array[i] is JsonObject) { - updateLivePreviewContent((JObject)array[i]); + updateLivePreviewContent((JsonObject)array[i]); } } } diff --git a/Contentstack.Core/Internals/JsonSerializerOptionsConverters.cs b/Contentstack.Core/Internals/JsonSerializerOptionsConverters.cs new file mode 100644 index 00000000..834e318f --- /dev/null +++ b/Contentstack.Core/Internals/JsonSerializerOptionsConverters.cs @@ -0,0 +1,68 @@ +using System; +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +public class CustomUtcDateTimeConverter : JsonConverter +{ + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + // Parse the string, treating it as UTC if no timezone is specified + if (DateTime.TryParse(reader.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out DateTime dateTime)) + { + return dateTime.Kind == DateTimeKind.Unspecified + ? DateTime.SpecifyKind(dateTime, DateTimeKind.Utc) + : dateTime; + } + } + + return reader.GetDateTime(); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + // Ensure the datetime is in UTC when writing + writer.WriteStringValue(value.Kind == DateTimeKind.Local + ? value.ToUniversalTime() + : value); + } +} + +public class CustomNullableUtcDateTimeConverter : JsonConverter +{ + public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + return null; + + if (reader.TokenType == JsonTokenType.String) + { + // Parse the string, treating it as UTC if no timezone is specified + if (DateTime.TryParse(reader.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out DateTime dateTime)) + { + return dateTime.Kind == DateTimeKind.Unspecified + ? DateTime.SpecifyKind(dateTime, DateTimeKind.Utc) + : dateTime; + } + } + + return reader.GetDateTime(); + } + + public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) + { + if (value.HasValue) + { + // Ensure the datetime is in UTC when writing + writer.WriteStringValue(value.Value.Kind == DateTimeKind.Local + ? value.Value.ToUniversalTime() + : value.Value); + } + else + { + writer.WriteNullValue(); + } + } +} \ No newline at end of file diff --git a/Contentstack.Core/Internals/StackOutput.cs b/Contentstack.Core/Internals/StackOutput.cs index a934059c..0b204897 100644 --- a/Contentstack.Core/Internals/StackOutput.cs +++ b/Contentstack.Core/Internals/StackOutput.cs @@ -1,8 +1,5 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; +using System; using System.Collections.Generic; -using System.Linq; namespace Contentstack.Core.Internals diff --git a/Contentstack.Core/Models/Asset.cs b/Contentstack.Core/Models/Asset.cs index 05756a2f..47355f8a 100644 --- a/Contentstack.Core/Models/Asset.cs +++ b/Contentstack.Core/Models/Asset.cs @@ -3,12 +3,13 @@ using System.IO; using System.Linq; using System.Net; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; using System.Threading.Tasks; using Contentstack.Core.Configuration; using Contentstack.Core.Internals; using Contentstack.Utils.Interfaces; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Contentstack.Core.Models { @@ -98,19 +99,19 @@ public string Url /// /// This is Asset type uid. /// - [JsonProperty(propertyName: "_content_type_uid")] + [JsonPropertyName("_content_type_uid")] public string ContentTypeUid { get; set; } /// /// The size of the file in bytes. /// - [JsonProperty(PropertyName = "file_size")] + [JsonPropertyName("file_size")] public string FileSize { get; set; } /// /// The original name of the file. /// - [JsonProperty(PropertyName = "filename")] + [JsonPropertyName("filename")] public string FileName { get; set; } /// @@ -126,50 +127,50 @@ public string Url /// /// This content_type in asset. /// - [JsonProperty(propertyName: "content_type")] + [JsonPropertyName("content_type")] public string ContentType { get; set; } /// /// This for whether it is asset directory /// - [JsonProperty(propertyName: "is_dir")] + [JsonPropertyName("is_dir")] public Boolean IsDir { get; set; } /// /// Uid of user who updated the file /// - [JsonProperty(PropertyName = "updated_by")] - public string UpdatedBy { get; set; } - + [JsonPropertyName("updated_by")] + public string UpdatedBy { get; set; } + /// /// Uid of user who updated the file /// - [JsonProperty(PropertyName = "created_by")] + [JsonPropertyName("created_by")] public string CreatedBy { get; set; } /// /// The Uid of folder in which the asset is present /// - [JsonProperty(PropertyName = "parent_uid")] + [JsonPropertyName("parent_uid")] public string ParentUid { get; set; } /// /// The Version of Asset /// - [JsonProperty(PropertyName = "_version")] + [JsonPropertyName("_version")] public string Version { get; set; } /// /// Dimension Object of the asset containing Height and width /// - [JsonProperty(PropertyName = "dimension")] + [JsonPropertyName("dimension")] public Dictionary Dimension { get; set; } /// /// Dimension Object of the asset containing Height and width /// - [JsonProperty(PropertyName = "publish_details")] + [JsonPropertyName("publish_details")] public Dictionary PublishDetails { get; set; } #region Internal Constructors @@ -306,9 +307,9 @@ public void RemoveHeader(string key) } - internal void ParseObject(JObject jsonObj) + internal void ParseObject(JsonElement jsonObj) { - this._ObjectAttributes = jsonObj.ToObject>(); + this._ObjectAttributes = JsonSerializer.Deserialize>(jsonObj); } public DateTime GetCreateAt() @@ -419,8 +420,9 @@ public async Task Fetch() { HttpRequestHandler RequestHandler = new HttpRequestHandler(this.StackInstance); var outputResult = await RequestHandler.ProcessRequest(_Url, headers, mainJson, Branch: this.StackInstance.Config.Branch, timeout: this.StackInstance.Config.Timeout, proxy: this.StackInstance.Config.Proxy); - JObject obj = JObject.Parse(ContentstackConvert.ToString(outputResult, "{}")); - return obj.SelectToken("$.asset").ToObject(this.StackInstance.Serializer); + JsonObject obj = JsonNode.Parse(ContentstackConvert.ToString(outputResult, "{}")).AsObject(); + // TODO: the serializer earlier taken was this.StackInstance.Serializer + return JsonSerializer.Deserialize(obj["$.asset"].ToJsonString(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); } catch (Exception ex) { @@ -486,21 +488,16 @@ internal static ContentstackException GetContentstackError(Exception ex) using (var reader = new StreamReader(stream)) { errorMessage = reader.ReadToEnd(); - JObject data = JObject.Parse(errorMessage.Replace("\r\n", "")); - //errorCode = ContentstackConvert.ToInt32(data.Property("error_code").Value); - //errorMessage = ContentstackConvert.ToString(data.Property("error_message").Value); + JsonObject data = JsonNode.Parse(errorMessage.Replace("\r\n", "")).AsObject(); - JToken token = data["error_code"]; - if (token != null) - errorCode = token.Value(); + if (data.TryGetPropertyValue("error_code", out JsonNode token)) + errorCode = token.GetValue(); - token = data["error_message"]; - if (token != null) - errorMessage = token.Value(); + if (data.TryGetPropertyValue("error_message", out token)) + errorMessage = token.GetValue(); - token = data["errors"]; - if (token != null) - errors = token.ToObject>(); + if (data.TryGetPropertyValue("errors", out token)) + errors = JsonSerializer.Deserialize>(token.ToJsonString()); var response = exResp as HttpWebResponse; if (response != null) diff --git a/Contentstack.Core/Models/AssetLibrary.cs b/Contentstack.Core/Models/AssetLibrary.cs index 2c7e88db..548a7a44 100644 --- a/Contentstack.Core/Models/AssetLibrary.cs +++ b/Contentstack.Core/Models/AssetLibrary.cs @@ -3,10 +3,11 @@ using System.IO; using System.Linq; using System.Net; +using System.Text.Json; +using System.Text.Json.Nodes; using System.Threading.Tasks; using Contentstack.Core.Configuration; using Contentstack.Core.Internals; -using Newtonsoft.Json.Linq; namespace Contentstack.Core.Models { @@ -86,13 +87,13 @@ public void SortWithKeyAndOrderBy(String key, OrderBy order) /// JObject jObject = await assetLibrary.Count(); /// /// - public async Task Count() + public async Task Count() { UrlQueries.Add("count", "true"); return await Exec(); } - public AssetLibrary Query(JObject QueryObject) + public AssetLibrary Query(JsonObject QueryObject) { try { @@ -435,9 +436,10 @@ public AssetLibrary RemoveHeader(string key) /// public async Task> FetchAll() { - JObject json = await Exec(); - var assets = json.SelectToken("$.assets").ToObject>(this.Stack.Serializer); - var collection = json.ToObject>(this.Stack.Serializer); + JsonObject json = await Exec(); + // TODO: the serializer earlier taken was this.StackInstance.Serializer + var assets = JsonSerializer.Deserialize>(json["assets"].ToJsonString(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + var collection = JsonSerializer.Deserialize>(json.ToJsonString(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); foreach (var entry in assets) { if (entry.GetType() == typeof(Asset)) @@ -449,7 +451,7 @@ public async Task> FetchAll() return collection; } - private async Task Exec() + private async Task Exec() { Dictionary headers = GetHeader(_Headers); @@ -474,7 +476,7 @@ private async Task Exec() { HttpRequestHandler RequestHandler = new HttpRequestHandler(this.Stack); var outputResult = await RequestHandler.ProcessRequest(_Url, headers, mainJson, Branch: this.Stack.Config.Branch, timeout: this.Stack.Config.Timeout, proxy: this.Stack.Config.Proxy); - return JObject.Parse(ContentstackConvert.ToString(outputResult, "{}")); + return JsonNode.Parse(ContentstackConvert.ToString(outputResult, "{}")).AsObject(); } catch (Exception ex) @@ -541,23 +543,22 @@ internal static ContentstackException GetContentstackError(Exception ex) using (var reader = new StreamReader(stream)) { errorMessage = reader.ReadToEnd(); - JObject data = JObject.Parse(errorMessage.Replace("\r\n", "")); + JsonObject data = JsonNode.Parse(errorMessage.Replace("\r\n", "")).AsObject(); - JToken token = data["error_code"]; - if (token != null) - errorCode = token.Value(); + if (data.TryGetPropertyValue("error_code", out JsonNode token)) + errorCode = token.GetValue(); - token = data["error_message"]; - if (token != null) - errorMessage = token.Value(); + if (data.TryGetPropertyValue("error_message", out token)) + errorMessage = token.GetValue(); - token = data["errors"]; - if (token != null) - errors = token.ToObject>(); + if (data.TryGetPropertyValue("errors", out token)) + errors = JsonSerializer.Deserialize>(token.ToJsonString()); var response = exResp as HttpWebResponse; if (response != null) + { statusCode = response.StatusCode; + } } } catch diff --git a/Contentstack.Core/Models/ContentType.cs b/Contentstack.Core/Models/ContentType.cs index 837d15aa..5642950e 100644 --- a/Contentstack.Core/Models/ContentType.cs +++ b/Contentstack.Core/Models/ContentType.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Threading.Tasks; using Contentstack.Core.Configuration; using Contentstack.Core.Internals; -using System.Threading.Tasks; -using System.Net; -using Newtonsoft.Json.Linq; -using System.Linq; -using System.IO; -using Newtonsoft.Json; namespace Contentstack.Core.Models { @@ -82,23 +82,22 @@ internal static ContentstackException GetContentstackError(Exception ex) using (var reader = new StreamReader(stream)) { errorMessage = reader.ReadToEnd(); - JObject data = JObject.Parse(errorMessage.Replace("\r\n", "")); + JsonObject data = JsonNode.Parse(errorMessage.Replace("\r\n", "")).AsObject(); - JToken token = data["error_code"]; - if (token != null) - errorCode = token.Value(); + if (data.TryGetPropertyValue("error_code", out JsonNode token)) + errorCode = token.GetValue(); - token = data["error_message"]; - if (token != null) - errorMessage = token.Value(); + if (data.TryGetPropertyValue("error_message", out token)) + errorMessage = token.GetValue(); - token = data["errors"]; - if (token != null) - errors = token.ToObject>(); + if (data.TryGetPropertyValue("errors", out token)) + errors = JsonSerializer.Deserialize>(token.ToJsonString()); var response = exResp as HttpWebResponse; if (response != null) + { statusCode = response.StatusCode; + } } } catch @@ -139,7 +138,7 @@ internal void SetStackInstance(ContentstackClient stack) /// /// is dictionary of additional parameter /// The Content-Type Schema Object. - public async Task Fetch(Dictionary param = null) + public async Task Fetch(Dictionary param = null) { Dictionary headers = GetHeader(_Headers); Dictionary headerAll = new Dictionary(); @@ -170,8 +169,8 @@ public async Task Fetch(Dictionary param = null) { HttpRequestHandler RequestHandler = new HttpRequestHandler(this.StackInstance); var outputResult = await RequestHandler.ProcessRequest(_Url, headers, mainJson, Branch: this.StackInstance.Config.Branch, timeout: this.StackInstance.Config.Timeout, proxy: this.StackInstance.Config.Proxy); - JObject data = JsonConvert.DeserializeObject(outputResult.Replace("\r\n", ""), this.StackInstance.SerializerSettings); - JObject contentTypes = (Newtonsoft.Json.Linq.JObject)data["content_type"]; + JsonObject data = JsonNode.Parse(outputResult.Replace("\r\n", "")).AsObject(); + JsonObject contentTypes = data["content_type"].AsObject(); return contentTypes; } catch (Exception ex) diff --git a/Contentstack.Core/Models/ContentstackCollection.cs b/Contentstack.Core/Models/ContentstackCollection.cs old mode 100755 new mode 100644 index 0edd7c6b..458f5d41 --- a/Contentstack.Core/Models/ContentstackCollection.cs +++ b/Contentstack.Core/Models/ContentstackCollection.cs @@ -1,14 +1,10 @@ -using Newtonsoft.Json; -using System; -using System.Collections; +using System.Collections; using System.Collections.Generic; -using System.Text; namespace Contentstack.Core.Models { - [JsonObject] - public class ContentstackCollection : IEnumerable - { + public class ContentstackCollection : IEnumerable + { /// /// The number of items skipped in this resultset. /// From a9dfb2468c8e338168f26c49174331db0c2b9adf Mon Sep 17 00:00:00 2001 From: Nadeem <110535104+nadeem-cs@users.noreply.github.com> Date: Wed, 26 Mar 2025 16:36:38 +0530 Subject: [PATCH 2/6] Revert "refactor: Updating to system.text.json" --- .github/workflows/jira.yml | 2 +- .github/workflows/sca-scan.yml | 12 +++- .talismanrc | 2 +- CODEOWNERS | 2 +- .../Configuration/LivePreviewConfig.cs | 6 +- Contentstack.Core/Contentstack.Core.csproj | 3 +- Contentstack.Core/ContentstackClient.cs | 67 +++++++++--------- .../Internals/AssetJsonConverter.cs | 24 +++---- .../Internals/ContentStackError.cs | 12 ++-- .../Internals/ContentstackConvert.cs | 6 +- .../Internals/HttpRequestHandler.cs | 34 +++++----- .../JsonSerializerOptionsConverters.cs | 68 ------------------- Contentstack.Core/Internals/StackOutput.cs | 5 +- Contentstack.Core/Models/Asset.cs | 59 ++++++++-------- Contentstack.Core/Models/AssetLibrary.cs | 37 +++++----- Contentstack.Core/Models/ContentType.cs | 37 +++++----- .../Models/ContentstackCollection.cs | 10 ++- 17 files changed, 172 insertions(+), 214 deletions(-) delete mode 100644 Contentstack.Core/Internals/JsonSerializerOptionsConverters.cs mode change 100644 => 100755 Contentstack.Core/Models/ContentstackCollection.cs diff --git a/.github/workflows/jira.yml b/.github/workflows/jira.yml index 250abc76..caa4bbdf 100644 --- a/.github/workflows/jira.yml +++ b/.github/workflows/jira.yml @@ -21,7 +21,7 @@ jobs: project: ${{ secrets.JIRA_PROJECT }} issuetype: ${{ secrets.JIRA_ISSUE_TYPE }} summary: | - Snyk | Vulnerability | ${{ github.event.repository.name }} | ${{ github.event.pull_request.title }} + ${{ github.event.pull_request.title }} description: | PR: ${{ github.event.pull_request.html_url }} diff --git a/.github/workflows/sca-scan.yml b/.github/workflows/sca-scan.yml index 4fa45607..decebb18 100644 --- a/.github/workflows/sca-scan.yml +++ b/.github/workflows/sca-scan.yml @@ -6,10 +6,18 @@ jobs: security-sca: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - name: Checkout repository + uses: actions/checkout@master + - name: Setup .NET Core @ Latest + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "7.0.x" + - name: Run Dotnet Restore + run: | + dotnet restore - name: Run Snyk to check for vulnerabilities uses: snyk/actions/dotnet@master env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: - args: --fail-on=all + args: --file=Contentstack.Core/obj/project.assets.json --fail-on=all diff --git a/.talismanrc b/.talismanrc index 51046293..2fd7ede5 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,6 +1,6 @@ fileignoreconfig: - filename: Contentstack.Core/Internals/HttpRequestHandler.cs - checksum: 29bb8548d65cdc5800fc939e526797bb3515f528d8082a58a0c9c6215dec1651 + checksum: 93c1659f3bc7527956f0fd12db46441297fac3a4366d273bcbb3425d2351300e - filename: Contentstack.Core/Models/Entry.cs checksum: 79320b005882981fd7c79fe73832f28284db686927942e46b422ac9e88405023 - filename: Contentstack.Core/ContentstackClient.cs diff --git a/CODEOWNERS b/CODEOWNERS index 1be7e0dc..07739234 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @contentstack/security-admin +* @contentstack/security-admin \ No newline at end of file diff --git a/Contentstack.Core/Configuration/LivePreviewConfig.cs b/Contentstack.Core/Configuration/LivePreviewConfig.cs index 0fbecdf9..240db8e1 100644 --- a/Contentstack.Core/Configuration/LivePreviewConfig.cs +++ b/Contentstack.Core/Configuration/LivePreviewConfig.cs @@ -1,4 +1,6 @@ -using System.Text.Json; +using System; +using System.Collections; +using Newtonsoft.Json.Linq; namespace Contentstack.Core.Configuration { @@ -11,6 +13,6 @@ public class LivePreviewConfig internal string LivePreview { get; set; } internal string ContentTypeUID { get; set; } internal string EntryUID { get; set; } - internal JsonElement PreviewResponse { get; set; } + internal JObject PreviewResponse { get; set; } } } diff --git a/Contentstack.Core/Contentstack.Core.csproj b/Contentstack.Core/Contentstack.Core.csproj index 4d4bb79c..030a3a79 100644 --- a/Contentstack.Core/Contentstack.Core.csproj +++ b/Contentstack.Core/Contentstack.Core.csproj @@ -1,7 +1,7 @@  - net7.0 + netstandard2.0;net47;net472; contentstack.csharp Contentstack .NET SDK for the Contentstack Content Delivery API. @@ -28,6 +28,7 @@ + diff --git a/Contentstack.Core/ContentstackClient.cs b/Contentstack.Core/ContentstackClient.cs index e76fe32c..b86d2f47 100644 --- a/Contentstack.Core/ContentstackClient.cs +++ b/Contentstack.Core/ContentstackClient.cs @@ -1,17 +1,18 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.IO; +using Contentstack.Core.Internals; +using Contentstack.Core.Configuration; +using Microsoft.Extensions.Options; +using Contentstack.Core.Models; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; using System.Linq; -using System.Net; -using System.Text.Json; -using System.Text.Json.Serialization; using System.Threading.Tasks; -using Contentstack.Core.Configuration; +using System.Net; +using System.IO; +using System.Collections; +using Contentstack.Utils; using Contentstack.Core.Interfaces; -using Contentstack.Core.Internals; -using Contentstack.Core.Models; -using Microsoft.Extensions.Options; namespace Contentstack.Core { @@ -23,16 +24,7 @@ public class ContentstackClient /// /// Gets or sets the settings that should be used for deserialization. /// - public JsonSerializerOptions SerializerSettings { get; set; } = new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - Converters = { - new JsonStringEnumConverter(), - new CustomUtcDateTimeConverter(), - new CustomNullableUtcDateTimeConverter(), - } - }; + public JsonSerializerSettings SerializerSettings { get; set; } = new JsonSerializerSettings(); #region Internal Variables @@ -43,6 +35,7 @@ internal string StackApiKey } private ContentstackOptions _options; + internal JsonSerializer Serializer => JsonSerializer.Create(SerializerSettings); internal string _SyncUrl { get @@ -140,6 +133,10 @@ public ContentstackClient(IOptions options) throw new InvalidOperationException("Add PreviewToken or ManagementToken in LivePreviewConfig"); } } + this.SerializerSettings.DateParseHandling = DateParseHandling.None; + this.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat; + this.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; + this.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; foreach (Type t in CSJsonConverterAttribute.GetCustomAttribute(typeof(CSJsonConverterAttribute))) { @@ -212,18 +209,22 @@ internal static ContentstackException GetContentstackError(Exception ex) using (var reader = new StreamReader(stream)) { errorMessage = reader.ReadToEnd(); - var data = JsonSerializer.Deserialize(errorMessage); + JObject data = JObject.Parse(errorMessage.Replace("\r\n", "")); - if (data.TryGetProperty("error_code", out var token)) - errorCode = token.GetInt32(); + JToken token = data["error_code"]; + if (token != null) + errorCode = token.Value(); - if (data.TryGetProperty("error_message", out token)) - errorMessage = token.GetString(); + token = data["error_message"]; + if (token != null) + errorMessage = token.Value(); - if (data.TryGetProperty("errors", out token)) - errors = JsonSerializer.Deserialize>(token.GetRawText()); + token = data["errors"]; + if (token != null) + errors = token.ToObject>(); - if (exResp is HttpWebResponse response) + var response = exResp as HttpWebResponse; + if (response != null) statusCode = response.StatusCode; } } @@ -325,8 +326,8 @@ public async Task GetContentTypes(Dictionary param = null { HttpRequestHandler RequestHandler = new HttpRequestHandler(this); var outputResult = await RequestHandler.ProcessRequest(_Url, headers, mainJson, Branch: this.Config.Branch, timeout: this.Config.Timeout, proxy: this.Config.Proxy); - var data = JsonSerializer.Deserialize(outputResult); - var contentTypes = data.GetProperty("content_types").EnumerateArray().ToList(); + JObject data = JsonConvert.DeserializeObject(outputResult.Replace("\r\n", ""), this.SerializerSettings); + IList contentTypes = (IList)data["content_types"]; return contentTypes; } catch (Exception ex) @@ -335,7 +336,7 @@ public async Task GetContentTypes(Dictionary param = null } } - private async Task GetLivePreviewData() + private async Task GetLivePreviewData() { Dictionary headerAll = new Dictionary(); @@ -367,8 +368,8 @@ private async Task GetLivePreviewData() { HttpRequestHandler RequestHandler = new HttpRequestHandler(this); var outputResult = await RequestHandler.ProcessRequest(String.Format("{0}/content_types/{1}/entries/{2}", this.Config.getLivePreviewUrl(this.LivePreviewConfig), this.LivePreviewConfig.ContentTypeUID, this.LivePreviewConfig.EntryUID), headerAll, mainJson, Branch: this.Config.Branch, isLivePreview: true, timeout: this.Config.Timeout, proxy: this.Config.Proxy); - var data = JsonSerializer.Deserialize(outputResult); - return data.GetProperty("entry"); + JObject data = JsonConvert.DeserializeObject(outputResult.Replace("\r\n", ""), this.SerializerSettings); + return (JObject)data["entry"]; } catch (Exception ex) { @@ -785,7 +786,7 @@ private async Task GetResultAsync(string Init = "false", SyncType Syn { HttpRequestHandler requestHandler = new HttpRequestHandler(this); string js = await requestHandler.ProcessRequest(_SyncUrl, _LocalHeaders, mainJson, Branch: this.Config.Branch, timeout: this.Config.Timeout, proxy: this.Config.Proxy); - SyncStack stackSyncOutput = JsonSerializer.Deserialize(js); + SyncStack stackSyncOutput = JsonConvert.DeserializeObject(js); return stackSyncOutput; } catch (Exception ex) diff --git a/Contentstack.Core/Internals/AssetJsonConverter.cs b/Contentstack.Core/Internals/AssetJsonConverter.cs index 96e581bd..9fc72150 100644 --- a/Contentstack.Core/Internals/AssetJsonConverter.cs +++ b/Contentstack.Core/Internals/AssetJsonConverter.cs @@ -1,27 +1,27 @@ using System; -using System.Text.Json; -using System.Text.Json.Serialization; +using Contentstack.Core; using Contentstack.Core.Models; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Contentstack.Core.Internals { [CSJsonConverter("AssetJsonConverter")] public class AssetJsonConverter : JsonConverter { - public override Asset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override Asset ReadJson(JsonReader reader, Type objectType, Asset existingValue, bool hasExistingValue, JsonSerializer serializer) { - using (JsonDocument document = JsonDocument.ParseValue(ref reader)) - { - JsonElement root = document.RootElement; - Asset asset = JsonSerializer.Deserialize(root.GetRawText(), options); - asset.ParseObject(root); - return asset; - } + JObject jObject = JObject.Load(reader); + JsonSerializerSettings SerializerSettings = new JsonSerializerSettings(); + JsonSerializer Serializer = JsonSerializer.Create(SerializerSettings); + Asset asset = jObject.ToObject(Serializer); + asset.ParseObject(jObject); + return asset; } - public override void Write(Utf8JsonWriter writer, Asset value, JsonSerializerOptions options) + public override void WriteJson(JsonWriter writer, Asset value, JsonSerializer serializer) { throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/Contentstack.Core/Internals/ContentStackError.cs b/Contentstack.Core/Internals/ContentStackError.cs index 52f9b564..cb37a803 100644 --- a/Contentstack.Core/Internals/ContentStackError.cs +++ b/Contentstack.Core/Internals/ContentStackError.cs @@ -1,8 +1,8 @@ -using System; +using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.Net; -using System.Text.Json.Serialization; - + namespace Contentstack.Core.Internals { /// @@ -33,7 +33,7 @@ public class ContentstackException : Exception /// /// This is error message. /// - [JsonPropertyName("error_message")] + [JsonProperty("error_message")] public string ErrorMessage { get @@ -50,13 +50,13 @@ public string ErrorMessage /// /// This is error code. /// - [JsonPropertyName("error_code")] + [JsonProperty("error_code")] public int ErrorCode { get; set; } /// /// Set of errors in detail. /// - [JsonPropertyName("errors")] + [JsonProperty("errors")] public Dictionary Errors { get; set; } #endregion diff --git a/Contentstack.Core/Internals/ContentstackConvert.cs b/Contentstack.Core/Internals/ContentstackConvert.cs index a35a2357..b2d4d742 100644 --- a/Contentstack.Core/Internals/ContentstackConvert.cs +++ b/Contentstack.Core/Internals/ContentstackConvert.cs @@ -1,5 +1,9 @@ -using System; +using Newtonsoft.Json; +using System; using System.IO; +using System.Net.NetworkInformation; +using System.Security.Cryptography; +using System.Text; using System.Text.RegularExpressions; namespace Contentstack.Core.Internals diff --git a/Contentstack.Core/Internals/HttpRequestHandler.cs b/Contentstack.Core/Internals/HttpRequestHandler.cs index e8710f00..6252f519 100644 --- a/Contentstack.Core/Internals/HttpRequestHandler.cs +++ b/Contentstack.Core/Internals/HttpRequestHandler.cs @@ -4,9 +4,9 @@ using System.Linq; using System.Net; using System.Text; -using System.Text.Json; -using System.Text.Json.Nodes; using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Contentstack.Core.Internals { @@ -35,7 +35,7 @@ public async Task ProcessRequest(string Url, Dictionary return value; } else if (kvp.Value is Dictionary) - value = JsonSerializer.Serialize(kvp.Value); + value = JsonConvert.SerializeObject(kvp.Value); else return String.Format("{0}={1}", kvp.Key, kvp.Value); @@ -75,7 +75,7 @@ public async Task ProcessRequest(string Url, Dictionary request = await plugin.OnRequest(client, request); }; - var serializedresult = JsonSerializer.Serialize(BodyJson); + var serializedresult = JsonConvert.SerializeObject(BodyJson); byte[] requestBody = Encoding.UTF8.GetBytes(serializedresult); StreamReader reader = null; HttpWebResponse response = null; @@ -108,42 +108,42 @@ public async Task ProcessRequest(string Url, Dictionary } - internal void updateLivePreviewContent(JsonObject response) + internal void updateLivePreviewContent(JObject response) { if (response.ContainsKey("uid") && response["uid"].ToString() == this.client.LivePreviewConfig.EntryUID) { - foreach (var property in this.client.LivePreviewConfig.PreviewResponse.AsObject()) + response.Merge(this.client.LivePreviewConfig.PreviewResponse, new JsonMergeSettings() { - response[property.Key] = property.Value; - } + MergeArrayHandling = MergeArrayHandling.Replace + }); } else { foreach (var content in response) { - if (content.Value is JsonArray) + if (content.Value.Type == JTokenType.Array) { - updateArray((JsonArray)response[content.Key]); + updateArray((JArray)response[content.Key]); } - else if (content.Value is JsonObject) + else if (content.Value.Type == JTokenType.Object) { - updateLivePreviewContent((JsonObject)response[content.Key]); + updateLivePreviewContent((JObject)response[content.Key]); } } } } - internal void updateArray(JsonArray array) + internal void updateArray(JArray array) { for (var i = 0; i < array.Count(); i++) { - if (array[i] is JsonArray) + if (array[i].Type == JTokenType.Array) { - updateArray((JsonArray)array[i]); + updateArray((JArray)array[i]); } - else if (array[i] is JsonObject) + else if (array[i].Type == JTokenType.Object) { - updateLivePreviewContent((JsonObject)array[i]); + updateLivePreviewContent((JObject)array[i]); } } } diff --git a/Contentstack.Core/Internals/JsonSerializerOptionsConverters.cs b/Contentstack.Core/Internals/JsonSerializerOptionsConverters.cs deleted file mode 100644 index 834e318f..00000000 --- a/Contentstack.Core/Internals/JsonSerializerOptionsConverters.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Globalization; -using System.Text.Json; -using System.Text.Json.Serialization; - -public class CustomUtcDateTimeConverter : JsonConverter -{ - public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.String) - { - // Parse the string, treating it as UTC if no timezone is specified - if (DateTime.TryParse(reader.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out DateTime dateTime)) - { - return dateTime.Kind == DateTimeKind.Unspecified - ? DateTime.SpecifyKind(dateTime, DateTimeKind.Utc) - : dateTime; - } - } - - return reader.GetDateTime(); - } - - public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) - { - // Ensure the datetime is in UTC when writing - writer.WriteStringValue(value.Kind == DateTimeKind.Local - ? value.ToUniversalTime() - : value); - } -} - -public class CustomNullableUtcDateTimeConverter : JsonConverter -{ - public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.Null) - return null; - - if (reader.TokenType == JsonTokenType.String) - { - // Parse the string, treating it as UTC if no timezone is specified - if (DateTime.TryParse(reader.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out DateTime dateTime)) - { - return dateTime.Kind == DateTimeKind.Unspecified - ? DateTime.SpecifyKind(dateTime, DateTimeKind.Utc) - : dateTime; - } - } - - return reader.GetDateTime(); - } - - public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) - { - if (value.HasValue) - { - // Ensure the datetime is in UTC when writing - writer.WriteStringValue(value.Value.Kind == DateTimeKind.Local - ? value.Value.ToUniversalTime() - : value.Value); - } - else - { - writer.WriteNullValue(); - } - } -} \ No newline at end of file diff --git a/Contentstack.Core/Internals/StackOutput.cs b/Contentstack.Core/Internals/StackOutput.cs index 0b204897..a934059c 100644 --- a/Contentstack.Core/Internals/StackOutput.cs +++ b/Contentstack.Core/Internals/StackOutput.cs @@ -1,5 +1,8 @@ -using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; using System.Collections.Generic; +using System.Linq; namespace Contentstack.Core.Internals diff --git a/Contentstack.Core/Models/Asset.cs b/Contentstack.Core/Models/Asset.cs index 47355f8a..05756a2f 100644 --- a/Contentstack.Core/Models/Asset.cs +++ b/Contentstack.Core/Models/Asset.cs @@ -3,13 +3,12 @@ using System.IO; using System.Linq; using System.Net; -using System.Text.Json; -using System.Text.Json.Nodes; -using System.Text.Json.Serialization; using System.Threading.Tasks; using Contentstack.Core.Configuration; using Contentstack.Core.Internals; using Contentstack.Utils.Interfaces; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Contentstack.Core.Models { @@ -99,19 +98,19 @@ public string Url /// /// This is Asset type uid. /// - [JsonPropertyName("_content_type_uid")] + [JsonProperty(propertyName: "_content_type_uid")] public string ContentTypeUid { get; set; } /// /// The size of the file in bytes. /// - [JsonPropertyName("file_size")] + [JsonProperty(PropertyName = "file_size")] public string FileSize { get; set; } /// /// The original name of the file. /// - [JsonPropertyName("filename")] + [JsonProperty(PropertyName = "filename")] public string FileName { get; set; } /// @@ -127,50 +126,50 @@ public string Url /// /// This content_type in asset. /// - [JsonPropertyName("content_type")] + [JsonProperty(propertyName: "content_type")] public string ContentType { get; set; } /// /// This for whether it is asset directory /// - [JsonPropertyName("is_dir")] + [JsonProperty(propertyName: "is_dir")] public Boolean IsDir { get; set; } /// /// Uid of user who updated the file /// - [JsonPropertyName("updated_by")] - public string UpdatedBy { get; set; } - + [JsonProperty(PropertyName = "updated_by")] + public string UpdatedBy { get; set; } + /// /// Uid of user who updated the file /// - [JsonPropertyName("created_by")] + [JsonProperty(PropertyName = "created_by")] public string CreatedBy { get; set; } /// /// The Uid of folder in which the asset is present /// - [JsonPropertyName("parent_uid")] + [JsonProperty(PropertyName = "parent_uid")] public string ParentUid { get; set; } /// /// The Version of Asset /// - [JsonPropertyName("_version")] + [JsonProperty(PropertyName = "_version")] public string Version { get; set; } /// /// Dimension Object of the asset containing Height and width /// - [JsonPropertyName("dimension")] + [JsonProperty(PropertyName = "dimension")] public Dictionary Dimension { get; set; } /// /// Dimension Object of the asset containing Height and width /// - [JsonPropertyName("publish_details")] + [JsonProperty(PropertyName = "publish_details")] public Dictionary PublishDetails { get; set; } #region Internal Constructors @@ -307,9 +306,9 @@ public void RemoveHeader(string key) } - internal void ParseObject(JsonElement jsonObj) + internal void ParseObject(JObject jsonObj) { - this._ObjectAttributes = JsonSerializer.Deserialize>(jsonObj); + this._ObjectAttributes = jsonObj.ToObject>(); } public DateTime GetCreateAt() @@ -420,9 +419,8 @@ public async Task Fetch() { HttpRequestHandler RequestHandler = new HttpRequestHandler(this.StackInstance); var outputResult = await RequestHandler.ProcessRequest(_Url, headers, mainJson, Branch: this.StackInstance.Config.Branch, timeout: this.StackInstance.Config.Timeout, proxy: this.StackInstance.Config.Proxy); - JsonObject obj = JsonNode.Parse(ContentstackConvert.ToString(outputResult, "{}")).AsObject(); - // TODO: the serializer earlier taken was this.StackInstance.Serializer - return JsonSerializer.Deserialize(obj["$.asset"].ToJsonString(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + JObject obj = JObject.Parse(ContentstackConvert.ToString(outputResult, "{}")); + return obj.SelectToken("$.asset").ToObject(this.StackInstance.Serializer); } catch (Exception ex) { @@ -488,16 +486,21 @@ internal static ContentstackException GetContentstackError(Exception ex) using (var reader = new StreamReader(stream)) { errorMessage = reader.ReadToEnd(); - JsonObject data = JsonNode.Parse(errorMessage.Replace("\r\n", "")).AsObject(); + JObject data = JObject.Parse(errorMessage.Replace("\r\n", "")); + //errorCode = ContentstackConvert.ToInt32(data.Property("error_code").Value); + //errorMessage = ContentstackConvert.ToString(data.Property("error_message").Value); - if (data.TryGetPropertyValue("error_code", out JsonNode token)) - errorCode = token.GetValue(); + JToken token = data["error_code"]; + if (token != null) + errorCode = token.Value(); - if (data.TryGetPropertyValue("error_message", out token)) - errorMessage = token.GetValue(); + token = data["error_message"]; + if (token != null) + errorMessage = token.Value(); - if (data.TryGetPropertyValue("errors", out token)) - errors = JsonSerializer.Deserialize>(token.ToJsonString()); + token = data["errors"]; + if (token != null) + errors = token.ToObject>(); var response = exResp as HttpWebResponse; if (response != null) diff --git a/Contentstack.Core/Models/AssetLibrary.cs b/Contentstack.Core/Models/AssetLibrary.cs index 548a7a44..2c7e88db 100644 --- a/Contentstack.Core/Models/AssetLibrary.cs +++ b/Contentstack.Core/Models/AssetLibrary.cs @@ -3,11 +3,10 @@ using System.IO; using System.Linq; using System.Net; -using System.Text.Json; -using System.Text.Json.Nodes; using System.Threading.Tasks; using Contentstack.Core.Configuration; using Contentstack.Core.Internals; +using Newtonsoft.Json.Linq; namespace Contentstack.Core.Models { @@ -87,13 +86,13 @@ public void SortWithKeyAndOrderBy(String key, OrderBy order) /// JObject jObject = await assetLibrary.Count(); /// /// - public async Task Count() + public async Task Count() { UrlQueries.Add("count", "true"); return await Exec(); } - public AssetLibrary Query(JsonObject QueryObject) + public AssetLibrary Query(JObject QueryObject) { try { @@ -436,10 +435,9 @@ public AssetLibrary RemoveHeader(string key) /// public async Task> FetchAll() { - JsonObject json = await Exec(); - // TODO: the serializer earlier taken was this.StackInstance.Serializer - var assets = JsonSerializer.Deserialize>(json["assets"].ToJsonString(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); - var collection = JsonSerializer.Deserialize>(json.ToJsonString(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + JObject json = await Exec(); + var assets = json.SelectToken("$.assets").ToObject>(this.Stack.Serializer); + var collection = json.ToObject>(this.Stack.Serializer); foreach (var entry in assets) { if (entry.GetType() == typeof(Asset)) @@ -451,7 +449,7 @@ public async Task> FetchAll() return collection; } - private async Task Exec() + private async Task Exec() { Dictionary headers = GetHeader(_Headers); @@ -476,7 +474,7 @@ private async Task Exec() { HttpRequestHandler RequestHandler = new HttpRequestHandler(this.Stack); var outputResult = await RequestHandler.ProcessRequest(_Url, headers, mainJson, Branch: this.Stack.Config.Branch, timeout: this.Stack.Config.Timeout, proxy: this.Stack.Config.Proxy); - return JsonNode.Parse(ContentstackConvert.ToString(outputResult, "{}")).AsObject(); + return JObject.Parse(ContentstackConvert.ToString(outputResult, "{}")); } catch (Exception ex) @@ -543,22 +541,23 @@ internal static ContentstackException GetContentstackError(Exception ex) using (var reader = new StreamReader(stream)) { errorMessage = reader.ReadToEnd(); - JsonObject data = JsonNode.Parse(errorMessage.Replace("\r\n", "")).AsObject(); + JObject data = JObject.Parse(errorMessage.Replace("\r\n", "")); - if (data.TryGetPropertyValue("error_code", out JsonNode token)) - errorCode = token.GetValue(); + JToken token = data["error_code"]; + if (token != null) + errorCode = token.Value(); - if (data.TryGetPropertyValue("error_message", out token)) - errorMessage = token.GetValue(); + token = data["error_message"]; + if (token != null) + errorMessage = token.Value(); - if (data.TryGetPropertyValue("errors", out token)) - errors = JsonSerializer.Deserialize>(token.ToJsonString()); + token = data["errors"]; + if (token != null) + errors = token.ToObject>(); var response = exResp as HttpWebResponse; if (response != null) - { statusCode = response.StatusCode; - } } } catch diff --git a/Contentstack.Core/Models/ContentType.cs b/Contentstack.Core/Models/ContentType.cs index 5642950e..837d15aa 100644 --- a/Contentstack.Core/Models/ContentType.cs +++ b/Contentstack.Core/Models/ContentType.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text.Json; -using System.Text.Json.Nodes; -using System.Threading.Tasks; using Contentstack.Core.Configuration; using Contentstack.Core.Internals; +using System.Threading.Tasks; +using System.Net; +using Newtonsoft.Json.Linq; +using System.Linq; +using System.IO; +using Newtonsoft.Json; namespace Contentstack.Core.Models { @@ -82,22 +82,23 @@ internal static ContentstackException GetContentstackError(Exception ex) using (var reader = new StreamReader(stream)) { errorMessage = reader.ReadToEnd(); - JsonObject data = JsonNode.Parse(errorMessage.Replace("\r\n", "")).AsObject(); + JObject data = JObject.Parse(errorMessage.Replace("\r\n", "")); - if (data.TryGetPropertyValue("error_code", out JsonNode token)) - errorCode = token.GetValue(); + JToken token = data["error_code"]; + if (token != null) + errorCode = token.Value(); - if (data.TryGetPropertyValue("error_message", out token)) - errorMessage = token.GetValue(); + token = data["error_message"]; + if (token != null) + errorMessage = token.Value(); - if (data.TryGetPropertyValue("errors", out token)) - errors = JsonSerializer.Deserialize>(token.ToJsonString()); + token = data["errors"]; + if (token != null) + errors = token.ToObject>(); var response = exResp as HttpWebResponse; if (response != null) - { statusCode = response.StatusCode; - } } } catch @@ -138,7 +139,7 @@ internal void SetStackInstance(ContentstackClient stack) /// /// is dictionary of additional parameter /// The Content-Type Schema Object. - public async Task Fetch(Dictionary param = null) + public async Task Fetch(Dictionary param = null) { Dictionary headers = GetHeader(_Headers); Dictionary headerAll = new Dictionary(); @@ -169,8 +170,8 @@ public async Task Fetch(Dictionary param = null) { HttpRequestHandler RequestHandler = new HttpRequestHandler(this.StackInstance); var outputResult = await RequestHandler.ProcessRequest(_Url, headers, mainJson, Branch: this.StackInstance.Config.Branch, timeout: this.StackInstance.Config.Timeout, proxy: this.StackInstance.Config.Proxy); - JsonObject data = JsonNode.Parse(outputResult.Replace("\r\n", "")).AsObject(); - JsonObject contentTypes = data["content_type"].AsObject(); + JObject data = JsonConvert.DeserializeObject(outputResult.Replace("\r\n", ""), this.StackInstance.SerializerSettings); + JObject contentTypes = (Newtonsoft.Json.Linq.JObject)data["content_type"]; return contentTypes; } catch (Exception ex) diff --git a/Contentstack.Core/Models/ContentstackCollection.cs b/Contentstack.Core/Models/ContentstackCollection.cs old mode 100644 new mode 100755 index 458f5d41..0edd7c6b --- a/Contentstack.Core/Models/ContentstackCollection.cs +++ b/Contentstack.Core/Models/ContentstackCollection.cs @@ -1,10 +1,14 @@ -using System.Collections; +using Newtonsoft.Json; +using System; +using System.Collections; using System.Collections.Generic; +using System.Text; namespace Contentstack.Core.Models { - public class ContentstackCollection : IEnumerable - { + [JsonObject] + public class ContentstackCollection : IEnumerable + { /// /// The number of items skipped in this resultset. /// From d5db5fe8ad3a5229d645806edb79d2464cfb8e17 Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Tue, 29 Apr 2025 16:33:48 +0530 Subject: [PATCH 3/6] fix: delete workflow files --- .github/workflows/jira.yml | 33 --------------------------------- .github/workflows/sast-scan.yml | 11 ----------- 2 files changed, 44 deletions(-) delete mode 100644 .github/workflows/jira.yml delete mode 100644 .github/workflows/sast-scan.yml diff --git a/.github/workflows/jira.yml b/.github/workflows/jira.yml deleted file mode 100644 index caa4bbdf..00000000 --- a/.github/workflows/jira.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Create JIRA ISSUE -on: - pull_request: - types: [opened] -jobs: - security-jira: - if: ${{ github.actor == 'dependabot[bot]' || github.actor == 'snyk-bot' || contains(github.event.pull_request.head.ref, 'snyk-fix-') || contains(github.event.pull_request.head.ref, 'snyk-upgrade-')}} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Login into JIRA - uses: atlassian/gajira-login@master - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} - - name: Create a JIRA Issue - id: create - uses: atlassian/gajira-create@master - with: - project: ${{ secrets.JIRA_PROJECT }} - issuetype: ${{ secrets.JIRA_ISSUE_TYPE }} - summary: | - ${{ github.event.pull_request.title }} - description: | - PR: ${{ github.event.pull_request.html_url }} - - fields: "${{ secrets.JIRA_FIELDS }}" - - name: Transition issue - uses: atlassian/gajira-transition@v3 - with: - issue: ${{ steps.create.outputs.issue }} - transition: ${{ secrets.JIRA_TRANSITION }} diff --git a/.github/workflows/sast-scan.yml b/.github/workflows/sast-scan.yml deleted file mode 100644 index 3b9521a5..00000000 --- a/.github/workflows/sast-scan.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: SAST Scan -on: - pull_request: - types: [opened, synchronize, reopened] -jobs: - security-sast: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Semgrep Scan - run: docker run -v /var/run/docker.sock:/var/run/docker.sock -v "${PWD}:/src" returntocorp/semgrep semgrep scan --config auto \ No newline at end of file From 21d4f80acaeee274b98a323564ab77e9fb1cf5b4 Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Mon, 14 Jul 2025 17:33:44 +0530 Subject: [PATCH 4/6] fix: token issue --- CHANGELOG.md | 6 ++++++ Contentstack.Core/Models/Query.cs | 22 ++++++++++++++++++++-- Directory.Build.props | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14b0d61b..4f1bb708 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### Version: 2.22.2 +#### Date: July-14-2025 + +##### Fix: +- Fixed token issue for Live Preview + ### Version: 2.22.1 #### Date: June-13-2025 diff --git a/Contentstack.Core/Models/Query.cs b/Contentstack.Core/Models/Query.cs index 252cd424..b864a464 100644 --- a/Contentstack.Core/Models/Query.cs +++ b/Contentstack.Core/Models/Query.cs @@ -1886,11 +1886,11 @@ private async Task Exec() if (this.ContentTypeInstance!=null && this.ContentTypeInstance?.StackInstance.LivePreviewConfig.Enable == true && this.ContentTypeInstance?.StackInstance.LivePreviewConfig.ContentTypeUID == this.ContentTypeInstance?.ContentTypeId && header.Key == "access_token" - && isLivePreview) + && !string.IsNullOrEmpty(this.ContentTypeInstance.StackInstance.LivePreviewConfig.LivePreview)) { continue; } - headerAll.Add(header.Key, (string)header.Value); + headerAll.Add(header.Key, (String)header.Value); } } @@ -1941,7 +1941,25 @@ private async Task Exec() } else { + // console.WriteLine url, mainjson and headerAll + Console.WriteLine("=========================="); + Console.WriteLine(this._Url); + + foreach (var kvp in mainJson) + { + if (kvp.Key == "live_preview") + { + Console.WriteLine("mainjson=================="); + Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}"); + } + } + Console.WriteLine("headerAll=================="); + foreach (var kvp in headerAll) + { + Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}"); + } HttpRequestHandler requestHandler = new HttpRequestHandler(this.ContentTypeInstance.StackInstance); + Console.WriteLine(_Url); var outputResult = await requestHandler.ProcessRequest(_Url, headerAll, mainJson, Branch: this.ContentTypeInstance.StackInstance.Config.Branch, isLivePreview: isLivePreview, timeout: this.ContentTypeInstance.StackInstance.Config.Timeout); return JObject.Parse(ContentstackConvert.ToString(outputResult, "{}")); } diff --git a/Directory.Build.props b/Directory.Build.props index bec8fed7..cff023c3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - 2.22.1 + 2.22.2 From 37e206b5895bedda2785d86f56f16e1f2a4478ad Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Mon, 14 Jul 2025 17:38:37 +0530 Subject: [PATCH 5/6] fix: remove console logs --- Contentstack.Core/Models/Query.cs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/Contentstack.Core/Models/Query.cs b/Contentstack.Core/Models/Query.cs index b864a464..c50a09e2 100644 --- a/Contentstack.Core/Models/Query.cs +++ b/Contentstack.Core/Models/Query.cs @@ -1941,25 +1941,7 @@ private async Task Exec() } else { - // console.WriteLine url, mainjson and headerAll - Console.WriteLine("=========================="); - Console.WriteLine(this._Url); - - foreach (var kvp in mainJson) - { - if (kvp.Key == "live_preview") - { - Console.WriteLine("mainjson=================="); - Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}"); - } - } - Console.WriteLine("headerAll=================="); - foreach (var kvp in headerAll) - { - Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}"); - } HttpRequestHandler requestHandler = new HttpRequestHandler(this.ContentTypeInstance.StackInstance); - Console.WriteLine(_Url); var outputResult = await requestHandler.ProcessRequest(_Url, headerAll, mainJson, Branch: this.ContentTypeInstance.StackInstance.Config.Branch, isLivePreview: isLivePreview, timeout: this.ContentTypeInstance.StackInstance.Config.Timeout); return JObject.Parse(ContentstackConvert.ToString(outputResult, "{}")); } From dad8ad20f6b988b63397de117d10fce16d3df383 Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Mon, 14 Jul 2025 17:51:51 +0530 Subject: [PATCH 6/6] talisman update --- .talismanrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.talismanrc b/.talismanrc index 3871661e..5106f4c4 100644 --- a/.talismanrc +++ b/.talismanrc @@ -13,7 +13,7 @@ fileignoreconfig: - filename: Contentstack.Core/Models/Asset.cs checksum: d192718723e6cb2aa8f08f873d3a7ea7268c89cc15da3bdeea4c16fd304c410e - filename: Contentstack.Core/Models/Query.cs - checksum: fb9b5e4014f937d66b9028b35ea53d750e4d2659daaa48a2941c02f37429725f + checksum: 5816324addf20bc9ed66496ed3f18a90a2a140763378f899798d2d3b019c5f14 - filename: Contentstack.Core/Models/Taxonomy.cs checksum: 751a725d94eff7d845bb22a5ce80a5529bb62971373de39288149fff3d024930 - filename: .github/workflows/nuget-publish.yml