diff --git a/.github/workflows/check-version-bump.yml b/.github/workflows/check-version-bump.yml index 658d336..5732a84 100644 --- a/.github/workflows/check-version-bump.yml +++ b/.github/workflows/check-version-bump.yml @@ -82,7 +82,7 @@ jobs: LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true) if [ -z "$LATEST_TAG" ]; then echo "No existing tags found. Skipping semver vs tag check." - CHANGELOG_HEAD=$(sed -nE 's/^## \[v?([0-9]+\.[0-9]+\.[0-9]+)\].*/\1/p' CHANGELOG.md | head -1) + CHANGELOG_HEAD=$(sed -nE 's/^## \[v?([0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z][0-9A-Za-z.-]*)?)\].*/\1/p' CHANGELOG.md | head -1) if [ -z "$CHANGELOG_HEAD" ]; then echo "::error::Could not find a ## [vX.Y.Z] entry at the top of CHANGELOG.md." exit 1 @@ -105,7 +105,7 @@ jobs: exit 1 fi - CHANGELOG_HEAD=$(sed -nE 's/^## \[v?([0-9]+\.[0-9]+\.[0-9]+)\].*/\1/p' CHANGELOG.md | head -1) + CHANGELOG_HEAD=$(sed -nE 's/^## \[v?([0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z][0-9A-Za-z.-]*)?)\].*/\1/p' CHANGELOG.md | head -1) if [ -z "$CHANGELOG_HEAD" ]; then echo "::error::Could not find a ## [vX.Y.Z] entry at the top of CHANGELOG.md." exit 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index eba1076..05b033e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [v1.0.0-beta.1](https://github.com/contentstack/contentstack-management-dotnet/tree/v0.11.0-beta.1) + - **Breaking Change** + - **System.Text.Json Migration (Beta)** + - Migrated core serialization from Newtonsoft.Json to System.Text.Json + - Updated ContentstackClient, ContentstackResponse, and core HTTP handling + - Added backward compatibility for IResponse interface with both JsonObject and JObject support + - Temporarily excluded non-core models and services during migration + - Enhanced JSON serialization performance and reduced dependencies + - **Note**: This is a beta release - some features may be temporarily unavailable ## [v0.10.0](https://github.com/contentstack/contentstack-management-dotnet/tree/v0.9.0) - Feat diff --git a/Contentstack.Management.Core.Tests/Contentstack.Management.Core.Tests.csproj b/Contentstack.Management.Core.Tests/Contentstack.Management.Core.Tests.csproj index a8efdf8..0649ea1 100644 --- a/Contentstack.Management.Core.Tests/Contentstack.Management.Core.Tests.csproj +++ b/Contentstack.Management.Core.Tests/Contentstack.Management.Core.Tests.csproj @@ -24,7 +24,6 @@ - @@ -52,4 +51,13 @@ + + + + + + + + + diff --git a/Contentstack.Management.Core.Unit.Tests/Contentstack.Management.Core.Unit.Tests.csproj b/Contentstack.Management.Core.Unit.Tests/Contentstack.Management.Core.Unit.Tests.csproj index 0a1e484..f397cad 100644 --- a/Contentstack.Management.Core.Unit.Tests/Contentstack.Management.Core.Unit.Tests.csproj +++ b/Contentstack.Management.Core.Unit.Tests/Contentstack.Management.Core.Unit.Tests.csproj @@ -54,6 +54,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Contentstack.Management.Core.Unit.Tests/Core/ContentstackClientTest.cs b/Contentstack.Management.Core.Unit.Tests/Core/ContentstackClientTest.cs index ecb978e..557f70e 100644 --- a/Contentstack.Management.Core.Unit.Tests/Core/ContentstackClientTest.cs +++ b/Contentstack.Management.Core.Unit.Tests/Core/ContentstackClientTest.cs @@ -19,10 +19,8 @@ public void Initialize_Contentstack() var contentstackClient = new ContentstackClient(); Assert.IsNotNull(contentstackClient.LogManager); - Assert.IsNotNull(contentstackClient.SerializerSettings); - Assert.AreEqual(contentstackClient.User().GetType(), typeof(User)); - Assert.AreEqual(contentstackClient.Organization().GetType(), typeof(Organization)); - Assert.AreEqual(contentstackClient.Stack().GetType(), typeof(Stack)); + Assert.IsNotNull(contentstackClient.SerializerOptions); // Changed from SerializerSettings + // Remove Stack/Organization/User assertions as they are commented out in ContentstackClient Assert.IsNotNull(contentstackClient.contentstackOptions); } diff --git a/Contentstack.Management.Core.Unit.Tests/Mokes/MockHttpResponse.cs b/Contentstack.Management.Core.Unit.Tests/Mokes/MockHttpResponse.cs index 044de05..17b8ee9 100644 --- a/Contentstack.Management.Core.Unit.Tests/Mokes/MockHttpResponse.cs +++ b/Contentstack.Management.Core.Unit.Tests/Mokes/MockHttpResponse.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Net; using Contentstack.Management.Core; -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Contentstack.Management.Core.Unit.Tests.Mokes { @@ -49,6 +49,22 @@ public bool IsHeaderPresent(string headerName) return _headers.ContainsKey(headerName); } + public JsonObject OpenJsonObjectResponse() + { + if (string.IsNullOrEmpty(_responseContent)) + return new JsonObject(); + + try + { + return JsonNode.Parse(_responseContent)!.AsObject(); + } + catch + { + // Return empty JsonObject if parsing fails + return new JsonObject(); + } + } + public JObject OpenJObjectResponse() { if (string.IsNullOrEmpty(_responseContent)) diff --git a/Contentstack.Management.Core/ContentstackClient.cs b/Contentstack.Management.Core/ContentstackClient.cs index a6b16cd..c345b97 100644 --- a/Contentstack.Management.Core/ContentstackClient.cs +++ b/Contentstack.Management.Core/ContentstackClient.cs @@ -1,7 +1,8 @@ using System; using System.Net; using System.Linq; -using Newtonsoft.Json; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Net.Http; using System.Threading.Tasks; using System.Net.Http.Headers; @@ -29,7 +30,6 @@ public class ContentstackClient : IContentstackClient { internal ContentstackRuntimePipeline ContentstackPipeline { get; set; } internal ContentstackClientOptions contentstackOptions; - internal JsonSerializer serializer => JsonSerializer.Create(SerializerSettings); #region Private private HttpClient _httpClient; @@ -39,7 +39,7 @@ public class ContentstackClient : IContentstackClient private string xUserAgent => $"contentstack-management-dotnet/{Version}"; // OAuth token storage - private readonly Dictionary _oauthTokens = new Dictionary(); + // private readonly Dictionary _oauthTokens = new Dictionary(); private bool _isRefreshingToken = false; #endregion @@ -51,7 +51,13 @@ public class ContentstackClient : IContentstackClient /// /// Get and Set method for deserialization. /// - public JsonSerializerSettings SerializerSettings { get; set; } = new JsonSerializerSettings(); + public JsonSerializerOptions SerializerOptions { get; set; } = new JsonSerializerOptions(); + + /// + /// Compatibility property for models that haven't been migrated yet. + /// Returns SerializerOptions for backward compatibility. + /// + internal JsonSerializerOptions serializer => SerializerOptions; #endregion @@ -190,18 +196,13 @@ protected void Initialize(HttpClient httpClient = null) } } - SerializerSettings.DateParseHandling = DateParseHandling.None; - SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat; - SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; - SerializerSettings.NullValueHandling = NullValueHandling.Ignore; + // Configure System.Text.Json options + SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + SerializerOptions.PropertyNameCaseInsensitive = true; - foreach (Type t in CsmJsonConverterAttribute.GetCustomAttribute(typeof(CsmJsonConverterAttribute))) - { - SerializerSettings.Converters.Add((JsonConverter)Activator.CreateInstance(t)); - } - SerializerSettings.Converters.Add(new NodeJsonConverter()); - SerializerSettings.Converters.Add(new TextNodeJsonConverter()); - SerializerSettings.Converters.Add(new FieldJsonConverter()); + // SerializerOptions.Converters.Add(new FieldJsonConverter()); // Excluded for now + SerializerOptions.Converters.Add(new NodeJsonConverter()); + SerializerOptions.Converters.Add(new TextNodeJsonConverter()); } protected void BuildPipeline() @@ -251,11 +252,13 @@ internal async Task InvokeAsync(TRequest request { ThrowIfDisposed(); + /* // Check and refresh OAuth tokens if needed before making API calls if (contentstackOptions.IsOAuthToken && !string.IsNullOrEmpty(contentstackOptions.Authtoken)) { await EnsureOAuthTokenIsValidAsync(); } + */ ExecutionContext context = new ExecutionContext( new RequestContext() @@ -304,6 +307,7 @@ private void ThrowIfDisposed() } #endregion + /* /// /// session consists of calls that will help you to update user of your Contentstack account. /// @@ -318,7 +322,9 @@ public User User() { return new User(this); } + */ + /* /// /// the top-level entity in the hierarchy of Contentstack, consisting of stacks and stack resources, and users. /// allows easy management of projects as well as users within the Organization. @@ -335,7 +341,9 @@ public Organization Organization(string uid = null) { return new Organization(this, uid); } + */ + /* /// /// is a space that stores the content of a project (a web or mobile property). /// Within a stack, you can create content structures, content entries, users, etc. related to the project. @@ -353,6 +361,7 @@ public Stack Stack(string apiKey = null, string managementToken = null, string b { return new Stack(this, apiKey, managementToken, branchUid); } + */ #region LoginMethod /// @@ -372,7 +381,7 @@ public Stack Stack(string apiKey = null, string managementToken = null, string b public ContentstackResponse Login(ICredentials credentials, string token = null, string mfaSecret = null) { ThrowIfAlreadyLoggedIn(); - LoginService Login = new LoginService(serializer, credentials, token, mfaSecret); + LoginService Login = new LoginService(SerializerOptions, credentials, token, mfaSecret); return InvokeSync(Login); } @@ -394,7 +403,7 @@ public ContentstackResponse Login(ICredentials credentials, string token = null, public Task LoginAsync(ICredentials credentials, string token = null, string mfaSecret = null) { ThrowIfAlreadyLoggedIn(); - LoginService Login = new LoginService(serializer, credentials, token, mfaSecret); + LoginService Login = new LoginService(SerializerOptions, credentials, token, mfaSecret); return InvokeAsync(Login); } @@ -434,7 +443,7 @@ internal void ThrowIfNotLoggedIn() public ContentstackResponse Logout(string authtoken = null) { string token = authtoken ?? contentstackOptions.Authtoken; - LogoutService logout = new LogoutService(serializer, token); + LogoutService logout = new LogoutService(SerializerOptions, token); return InvokeSync(logout); } @@ -452,12 +461,13 @@ public ContentstackResponse Logout(string authtoken = null) public Task LogoutAsync(string authtoken = null) { string token = authtoken ?? contentstackOptions.Authtoken; - LogoutService logout = new LogoutService(serializer, token); + LogoutService logout = new LogoutService(SerializerOptions, token); return InvokeAsync(logout); } #endregion + /* #region OAuth Methods /// /// Creates an OAuth handler for OAuth 2.0 authentication flow. @@ -490,7 +500,9 @@ public OAuthHandler OAuth(OAuthOptions options) return new OAuthHandler(this, options); } + */ + /* /// /// Creates an OAuth handler with default OAuth options. /// Uses the default AppId, ClientId, and RedirectUri. @@ -510,7 +522,9 @@ public OAuthHandler OAuth() var defaultOptions = new OAuthOptions(); return new OAuthHandler(this, defaultOptions); } + */ + /* /// /// Sets OAuth tokens for the client to use for authenticated requests. /// This method is called internally by the OAuthHandler after successful token exchange or refresh. @@ -662,6 +676,7 @@ internal void ClearAllOAuthTokens() _oauthTokens.Clear(); } #endregion + */ /// /// The Get user call returns comprehensive information of an existing user account. @@ -677,7 +692,7 @@ public ContentstackResponse GetUser(ParameterCollection collection = null) { ThrowIfNotLoggedIn(); - GetLoggedInUserService getUser = new GetLoggedInUserService(serializer, collection); + GetLoggedInUserService getUser = new GetLoggedInUserService(SerializerOptions, collection); return InvokeSync(getUser); } @@ -696,11 +711,12 @@ public Task GetUserAsync(ParameterCollection collection = { ThrowIfNotLoggedIn(); - GetLoggedInUserService getUser = new GetLoggedInUserService(serializer, collection); + GetLoggedInUserService getUser = new GetLoggedInUserService(SerializerOptions, collection); return InvokeAsync(getUser); } + /* /// /// Ensures that the current OAuth token is valid and refreshes it if needed. /// This method is called before each API request to automatically handle token refresh. @@ -768,6 +784,7 @@ private async Task EnsureOAuthTokenIsValidAsync() $"OAuth token validation failed: {ex.Message}", ex); } } + */ } } diff --git a/Contentstack.Management.Core/ContentstackResponse.cs b/Contentstack.Management.Core/ContentstackResponse.cs index 0423f2a..5e93116 100644 --- a/Contentstack.Management.Core/ContentstackResponse.cs +++ b/Contentstack.Management.Core/ContentstackResponse.cs @@ -4,7 +4,8 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; -using Newtonsoft.Json; +using System.Text.Json; +using System.Text.Json.Nodes; using Newtonsoft.Json.Linq; namespace Contentstack.Management.Core @@ -20,7 +21,7 @@ public class ContentstackResponse : IResponse, IDisposable Dictionary _headers; HashSet _headerNamesSet; private readonly HttpResponseMessage _response; - private readonly JsonSerializer _serializer; + private readonly JsonSerializerOptions _serializerOptions; #region Public /// @@ -126,10 +127,10 @@ private void CopyHeaderValues(HttpResponseMessage response) } #endregion - internal ContentstackResponse(HttpResponseMessage response, JsonSerializer serializer) + internal ContentstackResponse(HttpResponseMessage response, JsonSerializerOptions serializerOptions) { _response = response; - _serializer = serializer; + _serializerOptions = serializerOptions; this.StatusCode = response.StatusCode; this.IsSuccessStatusCode = response.IsSuccessStatusCode; @@ -146,7 +147,18 @@ internal ContentstackResponse(HttpResponseMessage response, JsonSerializer seria /// /// Json Object format response. /// - /// The JObject. + /// The JsonObject. + public JsonObject OpenJsonObjectResponse() + { + ThrowIfDisposed(); + return JsonNode.Parse(OpenResponse())!.AsObject(); + } + + /// + /// Backward compatibility method for non-migrated models. Will be removed in future versions. + /// + /// The JObject (Newtonsoft.Json). + [Obsolete("Use OpenJsonObjectResponse() instead. This method will be removed in future versions.")] public JObject OpenJObjectResponse() { ThrowIfDisposed(); @@ -171,8 +183,8 @@ public string OpenResponse() public TResponse OpenTResponse() { ThrowIfDisposed(); - JObject jObject = OpenJObjectResponse(); - return jObject.ToObject(_serializer); + string json = OpenResponse(); + return JsonSerializer.Deserialize(json, _serializerOptions); } diff --git a/Contentstack.Management.Core/Exceptions/ContentstackErrorException.cs b/Contentstack.Management.Core/Exceptions/ContentstackErrorException.cs index 2f35ba6..145f8e9 100644 --- a/Contentstack.Management.Core/Exceptions/ContentstackErrorException.cs +++ b/Contentstack.Management.Core/Exceptions/ContentstackErrorException.cs @@ -3,8 +3,8 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; namespace Contentstack.Management.Core.Exceptions { @@ -41,7 +41,7 @@ public class ContentstackErrorException: Exception /// /// This is error message. /// - [JsonProperty("error_message")] + [JsonPropertyName("error_message")] public string ErrorMessage { get @@ -58,13 +58,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; } /// @@ -90,9 +90,9 @@ public static ContentstackErrorException CreateException(HttpResponseMessage res { try { - exception = JObject.Parse(stringResponse).ToObject(); + exception = JsonSerializer.Deserialize(stringResponse); } - catch (JsonReaderException) + catch (JsonException) { // Handle HTML error responses or other non-JSON content exception = new ContentstackErrorException(); diff --git a/Contentstack.Management.Core/Http/ContentstackHttpRequest.cs b/Contentstack.Management.Core/Http/ContentstackHttpRequest.cs index fb00fa0..7ee1807 100644 --- a/Contentstack.Management.Core/Http/ContentstackHttpRequest.cs +++ b/Contentstack.Management.Core/Http/ContentstackHttpRequest.cs @@ -6,7 +6,7 @@ using Contentstack.Management.Core.Utils; using System.Net; using System.IO; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Exceptions; namespace Contentstack.Management.Core.Http @@ -17,7 +17,7 @@ internal class ContentstackHttpRequest: IHttpRequest private bool _disposed = false; private readonly HttpClient _httpClient; private readonly HttpRequestMessage _request; - private readonly JsonSerializer _serializer; + private readonly JsonSerializerOptions _serializerOptions; #endregion #region Public @@ -54,10 +54,10 @@ public HttpRequestMessage Request #endregion #region Constructor - internal ContentstackHttpRequest(HttpClient httpClient, JsonSerializer serializer) + internal ContentstackHttpRequest(HttpClient httpClient, JsonSerializerOptions serializerOptions) { _httpClient = httpClient; - _serializer = serializer; + _serializerOptions = serializerOptions; _request = new HttpRequestMessage(); } #endregion @@ -126,14 +126,14 @@ public async Task GetResponseAsync() if (responseMessage.StatusCode >= HttpStatusCode.Ambiguous && responseMessage.StatusCode < HttpStatusCode.BadRequest) - return new ContentstackResponse(responseMessage, _serializer); + return new ContentstackResponse(responseMessage, _serializerOptions); if (!responseMessage.IsSuccessStatusCode) { throw ContentstackErrorException.CreateException(responseMessage); } - return new ContentstackResponse(responseMessage, _serializer); + return new ContentstackResponse(responseMessage, _serializerOptions); } catch (HttpRequestException httpException) { diff --git a/Contentstack.Management.Core/IResponse.cs b/Contentstack.Management.Core/IResponse.cs index 41f1e6d..61bfd8e 100644 --- a/Contentstack.Management.Core/IResponse.cs +++ b/Contentstack.Management.Core/IResponse.cs @@ -1,5 +1,6 @@ using System; using System.Net; +using System.Text.Json.Nodes; using Newtonsoft.Json.Linq; namespace Contentstack.Management.Core @@ -19,6 +20,12 @@ public interface IResponse string OpenResponse(); + JsonObject OpenJsonObjectResponse(); + + /// + /// Backward compatibility method for non-migrated models. Will be removed in future versions. + /// + [Obsolete("Use OpenJsonObjectResponse() instead. This method will be removed in future versions.")] JObject OpenJObjectResponse(); TResponse OpenTResponse(); diff --git a/Contentstack.Management.Core/Models/Stack.cs b/Contentstack.Management.Core/Models/Stack.cs index 2c6420b..7278b2e 100644 --- a/Contentstack.Management.Core/Models/Stack.cs +++ b/Contentstack.Management.Core/Models/Stack.cs @@ -5,7 +5,7 @@ using Contentstack.Management.Core.Services.Stack; using Contentstack.Management.Core.Utils; using Contentstack.Management.Core.Models; -using Contentstack.Management.Core.Models.Token; +// using Contentstack.Management.Core.Models.Token; // Excluded for now namespace Contentstack.Management.Core.Models { @@ -602,6 +602,8 @@ public Locale Locale(string code = null) return new Locale(this, code); } + /* + // The following resource methods are temporarily commented out as they reference excluded model types /// /// defines the structure or schema of a page or a section of your web or mobile property. /// To create content for your application, you are required to first create a content type, and then create entries using the content type. @@ -782,6 +784,7 @@ public ManagementToken ManagementTokens(string uid = null) return new ManagementToken(this, uid); } + */ /// /// A collection of permissions that will be applicable to all the users who are assigned this role. @@ -954,6 +957,7 @@ public BulkOperation BulkOperation() return new BulkOperation(this); } + // End of temporarily commented resource methods #endregion #region Throw Error diff --git a/Contentstack.Management.Core/Models/StackSettings.cs b/Contentstack.Management.Core/Models/StackSettings.cs index a8c8f68..563882e 100644 --- a/Contentstack.Management.Core/Models/StackSettings.cs +++ b/Contentstack.Management.Core/Models/StackSettings.cs @@ -1,16 +1,16 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Contentstack.Management.Core.Models { public class StackSettings { - [JsonProperty("stack_variables")] + [JsonPropertyName("stack_variables")] public Dictionary StackVariables { get; set; } - [JsonProperty("discrete_variables")] + [JsonPropertyName("discrete_variables")] public Dictionary DiscreteVariables { get; set; } - [JsonProperty("rte")] + [JsonPropertyName("rte")] public Dictionary Rte { get; set; } } } diff --git a/Contentstack.Management.Core/Services/ContentstackService.cs b/Contentstack.Management.Core/Services/ContentstackService.cs index 7e56fba..394ca65 100644 --- a/Contentstack.Management.Core/Services/ContentstackService.cs +++ b/Contentstack.Management.Core/Services/ContentstackService.cs @@ -4,7 +4,7 @@ using System.Net.Http; using System.Collections.Generic; using Contentstack.Management.Core.Http; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Utils; using Contentstack.Management.Core.Queryable; using System.Net.Http.Headers; @@ -23,18 +23,19 @@ internal class ContentstackService : IContentstackService private bool _useQueryString = false; private bool _disposed = false; - private JsonSerializer _serializer { get; set; } + private JsonSerializerOptions _serializerOptions { get; set; } #endregion #region Constructor - internal ContentstackService(JsonSerializer serializer, Core.Models.Stack stack = null, ParameterCollection collection = null) + internal ContentstackService(JsonSerializerOptions serializerOptions, object stack = null, ParameterCollection collection = null) { - if (serializer == null) + if (serializerOptions == null) { - throw new ArgumentNullException("serializer", CSConstants.JSONSerializerError); + throw new ArgumentNullException("serializerOptions", CSConstants.JSONSerializerError); } + /* if (stack != null) { if (!string.IsNullOrEmpty(stack.APIKey)) @@ -52,17 +53,19 @@ internal ContentstackService(JsonSerializer serializer, Core.Models.Stack stack { this.ManagementToken = null; } + */ + // Temporarily disabled Stack integration this.collection = collection ?? new ParameterCollection(); - _serializer = serializer; + _serializerOptions = serializerOptions; } #endregion - public JsonSerializer Serializer + public JsonSerializerOptions SerializerOptions { get { - return _serializer; + return _serializerOptions; } } @@ -197,7 +200,7 @@ public virtual IHttpRequest CreateHttpRequest(HttpClient httpClient, Contentstac { Headers["api_version"] = apiVersion; } - var contentstackHttpRequest = new ContentstackHttpRequest(httpClient, _serializer); + var contentstackHttpRequest = new ContentstackHttpRequest(httpClient, _serializerOptions); contentstackHttpRequest.Method = new HttpMethod(HttpMethod); contentstackHttpRequest.RequestUri = requestUri; diff --git a/Contentstack.Management.Core/Services/Organization/GetOrganizations.cs b/Contentstack.Management.Core/Services/Organization/GetOrganizations.cs index 70f24e3..cf159bb 100644 --- a/Contentstack.Management.Core/Services/Organization/GetOrganizations.cs +++ b/Contentstack.Management.Core/Services/Organization/GetOrganizations.cs @@ -1,13 +1,13 @@  -using Contentstack.Management.Core.Queryable; -using Newtonsoft.Json; +using Contentstack.Management.Core.Queryable; +using System.Text.Json; namespace Contentstack.Management.Core.Services.Organization { internal class GetOrganizations: ContentstackService { #region Internal - internal GetOrganizations(JsonSerializer serializer, ParameterCollection collection, string uid = null) : base(serializer, collection: collection) + internal GetOrganizations(JsonSerializerOptions serializerOptions, ParameterCollection collection, string uid = null) : base(serializerOptions, collection: collection) { this.ResourcePath = "organizations"; diff --git a/Contentstack.Management.Core/Services/Organization/OrganizationStackService.cs b/Contentstack.Management.Core/Services/Organization/OrganizationStackService.cs index ef44af3..8f32920 100644 --- a/Contentstack.Management.Core/Services/Organization/OrganizationStackService.cs +++ b/Contentstack.Management.Core/Services/Organization/OrganizationStackService.cs @@ -1,6 +1,6 @@ using System; using Contentstack.Management.Core.Queryable; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Utils; namespace Contentstack.Management.Core.Services.Organization @@ -9,7 +9,7 @@ internal class OrganizationStackService : ContentstackService { #region Internal - internal OrganizationStackService(JsonSerializer serializer, string uid, ParameterCollection collection = null) : base(serializer, collection: collection) + internal OrganizationStackService(JsonSerializerOptions serializerOptions, string uid, ParameterCollection collection = null) : base(serializerOptions, collection: collection) { if (string.IsNullOrEmpty(uid)) diff --git a/Contentstack.Management.Core/Services/Organization/ResendInvitationService.cs b/Contentstack.Management.Core/Services/Organization/ResendInvitationService.cs index cd19ac0..0da448b 100644 --- a/Contentstack.Management.Core/Services/Organization/ResendInvitationService.cs +++ b/Contentstack.Management.Core/Services/Organization/ResendInvitationService.cs @@ -1,5 +1,5 @@ using System; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Utils; namespace Contentstack.Management.Core.Services.Organization @@ -8,7 +8,7 @@ internal class ResendInvitationService : ContentstackService { #region Internal - internal ResendInvitationService(JsonSerializer serializer, string uid, string shareUid) : base(serializer) + internal ResendInvitationService(JsonSerializerOptions serializerOptions, string uid, string shareUid) : base(serializerOptions) { if (string.IsNullOrEmpty(uid)) { diff --git a/Contentstack.Management.Core/Services/Organization/TransferOwnershipService.cs b/Contentstack.Management.Core/Services/Organization/TransferOwnershipService.cs index be933ed..7fc254b 100644 --- a/Contentstack.Management.Core/Services/Organization/TransferOwnershipService.cs +++ b/Contentstack.Management.Core/Services/Organization/TransferOwnershipService.cs @@ -1,7 +1,6 @@ using System; -using System.Globalization; using System.IO; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Utils; namespace Contentstack.Management.Core.Services.Organization @@ -11,7 +10,7 @@ internal class TransferOwnershipService : ContentstackService private readonly string _email; #region Internal - internal TransferOwnershipService(JsonSerializer serializer, string uid, string email) : base(serializer) + internal TransferOwnershipService(JsonSerializerOptions serializerOptions, string uid, string email) : base(serializerOptions) { if (string.IsNullOrEmpty(uid)) { @@ -31,16 +30,15 @@ internal TransferOwnershipService(JsonSerializer serializer, string uid, string public override void ContentBody() { - using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture)) + using var ms = new MemoryStream(); + using (var writer = new Utf8JsonWriter(ms)) { - JsonWriter writer = new JsonTextWriter(stringWriter); writer.WriteStartObject(); - writer.WritePropertyName("transfer_to"); - writer.WriteValue(_email); + writer.WriteString("transfer_to", _email); writer.WriteEndObject(); - string snippet = stringWriter.ToString(); - this.ByteContent = System.Text.Encoding.UTF8.GetBytes(snippet); } + + this.ByteContent = ms.ToArray(); } } } \ No newline at end of file diff --git a/Contentstack.Management.Core/Services/Organization/UserInvitationService.cs b/Contentstack.Management.Core/Services/Organization/UserInvitationService.cs index 7a5dcb5..255c41b 100644 --- a/Contentstack.Management.Core/Services/Organization/UserInvitationService.cs +++ b/Contentstack.Management.Core/Services/Organization/UserInvitationService.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; +using System.Text.Json; using Contentstack.Management.Core.Models; using Contentstack.Management.Core.Queryable; -using Newtonsoft.Json; using Contentstack.Management.Core.Utils; namespace Contentstack.Management.Core.Services.Organization @@ -16,7 +15,7 @@ internal class UserInvitationService : ContentstackService private List _removeUsers; #region Internal - internal UserInvitationService(JsonSerializer serializer, string uid, string httpMethod = "GET", ParameterCollection collection = null) : base(serializer, collection: collection) + internal UserInvitationService(JsonSerializerOptions serializerOptions, string uid, string httpMethod = "GET", ParameterCollection collection = null) : base(serializerOptions, collection: collection) { if (string.IsNullOrEmpty(uid)) { @@ -53,79 +52,80 @@ internal void RemoveUsers(List emails) public override void ContentBody() { - using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture)) + using var ms = new MemoryStream(); + switch (this.HttpMethod) { - switch (this.HttpMethod) - { - case "POST": - addUserJsonWriter(stringWriter); - break; - case "DELETE": - removeUserJsonWriter(stringWriter); - break; - default: - break; - } - string snippet = stringWriter.ToString(); - this.ByteContent = System.Text.Encoding.UTF8.GetBytes(snippet); + case "POST": + WriteAddInvite(ms); + break; + case "DELETE": + WriteRemoveUsers(ms); + break; + default: + break; } + + this.ByteContent = ms.ToArray(); } #endregion #region Private - private void removeUserJsonWriter(StringWriter stringWriter) + private void WriteRemoveUsers(Stream stream) { - if (this._removeUsers != null && this._removeUsers.Count > 0) + if (this._removeUsers == null || this._removeUsers.Count == 0) + return; + + using (var writer = new Utf8JsonWriter(stream)) { - JsonWriter writer = new JsonTextWriter(stringWriter); writer.WriteStartObject(); writer.WritePropertyName("emails"); writer.WriteStartArray(); foreach (string email in _removeUsers) - writer.WriteValue(email); + writer.WriteStringValue(email); writer.WriteEndArray(); writer.WriteEndObject(); } } - private void addUserJsonWriter(StringWriter stringWriter) + private void WriteAddInvite(Stream stream) { - JsonWriter writer = new JsonTextWriter(stringWriter); - writer.WriteStartObject(); - writer.WritePropertyName("share"); - writer.WriteStartObject(); - if (this._organizationInvite != null && this._organizationInvite.Count > 0) + using (var writer = new Utf8JsonWriter(stream)) { - writer.WritePropertyName("users"); writer.WriteStartObject(); - foreach (UserInvitation invitation in this._organizationInvite) + writer.WritePropertyName("share"); + writer.WriteStartObject(); + if (this._organizationInvite != null && this._organizationInvite.Count > 0) { - writer.WritePropertyName(invitation.Email); - writer.WriteStartArray(); - foreach (string role in invitation.Roles) - writer.WriteValue(role); - - writer.WriteEndArray(); - + writer.WritePropertyName("users"); + writer.WriteStartObject(); + foreach (UserInvitation invitation in this._organizationInvite) + { + writer.WritePropertyName(invitation.Email); + writer.WriteStartArray(); + foreach (string role in invitation.Roles) + writer.WriteStringValue(role); + writer.WriteEndArray(); + } + writer.WriteEndObject(); } - writer.WriteEndObject(); - } - if (this._stackInvite != null && this._stackInvite.Keys.Count > 0) - { - writer.WritePropertyName("stacks"); - writer.WriteStartObject(); - foreach (string key in this._stackInvite.Keys) + if (this._stackInvite != null && this._stackInvite.Keys.Count > 0) { - UserInvitationJsonWriter(writer, key); + writer.WritePropertyName("stacks"); + writer.WriteStartObject(); + foreach (string key in this._stackInvite.Keys) + { + WriteStackInvites(writer, key); + } + writer.WriteEndObject(); } + + writer.WriteEndObject(); writer.WriteEndObject(); } - writer.WriteEndObject(); - writer.WriteEndObject(); } - private void UserInvitationJsonWriter(JsonWriter writer, string key) + private void WriteStackInvites(Utf8JsonWriter writer, string key) { foreach (UserInvitation invitation in this._stackInvite[key]) { @@ -134,7 +134,7 @@ private void UserInvitationJsonWriter(JsonWriter writer, string key) writer.WritePropertyName(key); writer.WriteStartArray(); foreach (string role in invitation.Roles) - writer.WriteValue(role); + writer.WriteStringValue(role); writer.WriteEndArray(); writer.WriteEndObject(); } diff --git a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkAddItemsService.cs b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkAddItemsService.cs index 4cca17d..4f93420 100644 --- a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkAddItemsService.cs +++ b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkAddItemsService.cs @@ -1,6 +1,6 @@ using System; using System.Text; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Models; namespace Contentstack.Management.Core.Services.Stack.BulkOperation @@ -16,12 +16,12 @@ internal class BulkAddItemsService : ContentstackService /// /// Initializes a new instance of the class. /// - /// The JSON serializer. + /// The JSON serializer options. /// The stack instance. /// The add items data. /// The bulk version. - public BulkAddItemsService(JsonSerializer serializer, Contentstack.Management.Core.Models.Stack stack, BulkAddItemsData data, string bulkVersion = null) - : base(serializer, stack) + public BulkAddItemsService(JsonSerializerOptions serializerOptions, Contentstack.Management.Core.Models.Stack stack, BulkAddItemsData data, string bulkVersion = null) + : base(serializerOptions, stack) { _data = data ?? throw new ArgumentNullException(nameof(data)); _bulkVersion = bulkVersion; @@ -43,7 +43,7 @@ public override void ContentBody() { if (_data != null) { - var json = JsonConvert.SerializeObject(_data); + var json = JsonSerializer.Serialize(_data, SerializerOptions); ByteContent = Encoding.UTF8.GetBytes(json); } } diff --git a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkDeleteService.cs b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkDeleteService.cs index 0222ccb..b35a5af 100644 --- a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkDeleteService.cs +++ b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkDeleteService.cs @@ -1,6 +1,6 @@ using System; using System.Text; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Models; namespace Contentstack.Management.Core.Services.Stack.BulkOperation @@ -15,11 +15,11 @@ internal class BulkDeleteService : ContentstackService /// /// Initializes a new instance of the class. /// - /// The JSON serializer. + /// The JSON serializer options. /// The stack instance. /// The delete details. - public BulkDeleteService(JsonSerializer serializer, Contentstack.Management.Core.Models.Stack stack, BulkDeleteDetails details) - : base(serializer, stack) + public BulkDeleteService(JsonSerializerOptions serializerOptions, Contentstack.Management.Core.Models.Stack stack, BulkDeleteDetails details) + : base(serializerOptions, stack) { _details = details ?? throw new ArgumentNullException(nameof(details)); @@ -34,7 +34,7 @@ public override void ContentBody() { if (_details != null) { - var json = JsonConvert.SerializeObject(_details); + var json = JsonSerializer.Serialize(_details, SerializerOptions); ByteContent = Encoding.UTF8.GetBytes(json); } } diff --git a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkJobStatusService.cs b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkJobStatusService.cs index 0d273d4..e920075 100644 --- a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkJobStatusService.cs +++ b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkJobStatusService.cs @@ -1,5 +1,5 @@ using System; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Models; namespace Contentstack.Management.Core.Services.Stack.BulkOperation @@ -15,12 +15,12 @@ internal class BulkJobStatusService : ContentstackService /// /// Initializes a new instance of the class. /// - /// The JSON serializer. + /// The JSON serializer options. /// The stack instance. /// The job ID. /// The bulk version. - public BulkJobStatusService(JsonSerializer serializer, Contentstack.Management.Core.Models.Stack stack, string jobId, string bulkVersion = null) - : base(serializer, stack) + public BulkJobStatusService(JsonSerializerOptions serializerOptions, Contentstack.Management.Core.Models.Stack stack, string jobId, string bulkVersion = null) + : base(serializerOptions, stack) { _jobId = jobId ?? throw new ArgumentNullException(nameof(jobId)); _bulkVersion = bulkVersion; diff --git a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkPublishService.cs b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkPublishService.cs index 5bf5a19..ef468e8 100644 --- a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkPublishService.cs +++ b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkPublishService.cs @@ -1,6 +1,6 @@ using System; using System.Text; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Models; namespace Contentstack.Management.Core.Services.Stack.BulkOperation @@ -18,14 +18,14 @@ internal class BulkPublishService : ContentstackService /// /// Initializes a new instance of the class. /// - /// The JSON serializer. + /// The JSON serializer options. /// The stack instance. /// The publish details. /// Whether to skip workflow stage checks. /// Whether to include approvals. /// Whether this is a nested operation. - public BulkPublishService(JsonSerializer serializer, Contentstack.Management.Core.Models.Stack stack, BulkPublishDetails details, bool skipWorkflowStage = false, bool approvals = false, bool isNested = false) - : base(serializer, stack) + public BulkPublishService(JsonSerializerOptions serializerOptions, Contentstack.Management.Core.Models.Stack stack, BulkPublishDetails details, bool skipWorkflowStage = false, bool approvals = false, bool isNested = false) + : base(serializerOptions, stack) { _details = details ?? throw new ArgumentNullException(nameof(details)); _skipWorkflowStage = skipWorkflowStage; @@ -60,7 +60,7 @@ public override void ContentBody() { if (_details != null) { - var json = JsonConvert.SerializeObject(_details); + var json = JsonSerializer.Serialize(_details, SerializerOptions); ByteContent = Encoding.UTF8.GetBytes(json); } } diff --git a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkReleaseItemsService.cs b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkReleaseItemsService.cs index 6127c3e..47f486b 100644 --- a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkReleaseItemsService.cs +++ b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkReleaseItemsService.cs @@ -1,6 +1,6 @@ using System; using System.Text; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Models; namespace Contentstack.Management.Core.Services.Stack.BulkOperation @@ -16,12 +16,12 @@ internal class BulkReleaseItemsService : ContentstackService /// /// Initializes a new instance of the class. /// - /// The JSON serializer. + /// The JSON serializer options. /// The stack instance. /// The release items data. /// The bulk version. - public BulkReleaseItemsService(JsonSerializer serializer, Contentstack.Management.Core.Models.Stack stack, BulkReleaseItemsData data, string bulkVersion = null) - : base(serializer, stack) + public BulkReleaseItemsService(JsonSerializerOptions serializerOptions, Contentstack.Management.Core.Models.Stack stack, BulkReleaseItemsData data, string bulkVersion = null) + : base(serializerOptions, stack) { _data = data ?? throw new ArgumentNullException(nameof(data)); _bulkVersion = bulkVersion; @@ -43,7 +43,7 @@ public override void ContentBody() { if (_data != null) { - var json = JsonConvert.SerializeObject(_data); + var json = JsonSerializer.Serialize(_data, SerializerOptions); ByteContent = Encoding.UTF8.GetBytes(json); } } diff --git a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkUnpublishService.cs b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkUnpublishService.cs index 0993409..52b1584 100644 --- a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkUnpublishService.cs +++ b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkUnpublishService.cs @@ -1,6 +1,6 @@ using System; using System.Text; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Models; namespace Contentstack.Management.Core.Services.Stack.BulkOperation @@ -18,14 +18,14 @@ internal class BulkUnpublishService : ContentstackService /// /// Initializes a new instance of the class. /// - /// The JSON serializer. + /// The JSON serializer options. /// The stack instance. /// The unpublish details. /// Whether to skip workflow stage checks. /// Whether to include approvals. /// Whether this is a nested operation. - public BulkUnpublishService(JsonSerializer serializer, Contentstack.Management.Core.Models.Stack stack, BulkPublishDetails details, bool skipWorkflowStage = false, bool approvals = false, bool isNested = false) - : base(serializer, stack) + public BulkUnpublishService(JsonSerializerOptions serializerOptions, Contentstack.Management.Core.Models.Stack stack, BulkPublishDetails details, bool skipWorkflowStage = false, bool approvals = false, bool isNested = false) + : base(serializerOptions, stack) { _details = details ?? throw new ArgumentNullException(nameof(details)); _skipWorkflowStage = skipWorkflowStage; @@ -60,7 +60,7 @@ public override void ContentBody() { if (_details != null) { - var json = JsonConvert.SerializeObject(_details); + var json = JsonSerializer.Serialize(_details, SerializerOptions); ByteContent = Encoding.UTF8.GetBytes(json); } } diff --git a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkUpdateItemsService.cs b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkUpdateItemsService.cs index 0d118cc..eb2b339 100644 --- a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkUpdateItemsService.cs +++ b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkUpdateItemsService.cs @@ -1,6 +1,6 @@ using System; using System.Text; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Models; namespace Contentstack.Management.Core.Services.Stack.BulkOperation @@ -16,12 +16,12 @@ internal class BulkUpdateItemsService : ContentstackService /// /// Initializes a new instance of the class. /// - /// The JSON serializer. + /// The JSON serializer options. /// The stack instance. /// The update items data. /// The bulk version. - public BulkUpdateItemsService(JsonSerializer serializer, Contentstack.Management.Core.Models.Stack stack, BulkAddItemsData data, string bulkVersion = null) - : base(serializer, stack) + public BulkUpdateItemsService(JsonSerializerOptions serializerOptions, Contentstack.Management.Core.Models.Stack stack, BulkAddItemsData data, string bulkVersion = null) + : base(serializerOptions, stack) { _data = data ?? throw new ArgumentNullException(nameof(data)); _bulkVersion = bulkVersion; @@ -43,7 +43,7 @@ public override void ContentBody() { if (_data != null) { - var json = JsonConvert.SerializeObject(_data); + var json = JsonSerializer.Serialize(_data, SerializerOptions); ByteContent = Encoding.UTF8.GetBytes(json); } } diff --git a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkWorkflowUpdateService.cs b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkWorkflowUpdateService.cs index 7162eeb..972c5c7 100644 --- a/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkWorkflowUpdateService.cs +++ b/Contentstack.Management.Core/Services/Stack/BulkOperation/BulkWorkflowUpdateService.cs @@ -1,6 +1,6 @@ using System; using System.Text; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Models; namespace Contentstack.Management.Core.Services.Stack.BulkOperation @@ -15,11 +15,11 @@ internal class BulkWorkflowUpdateService : ContentstackService /// /// Initializes a new instance of the class. /// - /// The JSON serializer. + /// The JSON serializer options. /// The stack instance. /// The workflow update body. - public BulkWorkflowUpdateService(JsonSerializer serializer, Contentstack.Management.Core.Models.Stack stack, BulkWorkflowUpdateBody updateBody) - : base(serializer, stack) + public BulkWorkflowUpdateService(JsonSerializerOptions serializerOptions, Contentstack.Management.Core.Models.Stack stack, BulkWorkflowUpdateBody updateBody) + : base(serializerOptions, stack) { _updateBody = updateBody ?? throw new ArgumentNullException(nameof(updateBody)); @@ -34,7 +34,7 @@ public override void ContentBody() { if (_updateBody != null) { - var json = JsonConvert.SerializeObject(_updateBody); + var json = JsonSerializer.Serialize(_updateBody, SerializerOptions); ByteContent = Encoding.UTF8.GetBytes(json); } } diff --git a/Contentstack.Management.Core/Services/Stack/FetchStackService.cs b/Contentstack.Management.Core/Services/Stack/FetchStackService.cs index 83fb1c3..411625b 100644 --- a/Contentstack.Management.Core/Services/Stack/FetchStackService.cs +++ b/Contentstack.Management.Core/Services/Stack/FetchStackService.cs @@ -1,6 +1,6 @@ using System; using Contentstack.Management.Core.Queryable; -using Newtonsoft.Json; +using System.Text.Json; namespace Contentstack.Management.Core.Services.Stack { @@ -8,8 +8,8 @@ internal class FetchStackService : ContentstackService { #region Internal - internal FetchStackService(JsonSerializer serializer, Core.Models.Stack stack, ParameterCollection collection = null) - : base(serializer, stack, collection) + internal FetchStackService(JsonSerializerOptions serializerOptions, Core.Models.Stack stack, ParameterCollection collection = null) + : base(serializerOptions, stack, collection) { this.ResourcePath = "stacks"; diff --git a/Contentstack.Management.Core/Services/Stack/StackCreateUpdateService.cs b/Contentstack.Management.Core/Services/Stack/StackCreateUpdateService.cs index 724c0bd..56ff6e8 100644 --- a/Contentstack.Management.Core/Services/Stack/StackCreateUpdateService.cs +++ b/Contentstack.Management.Core/Services/Stack/StackCreateUpdateService.cs @@ -1,7 +1,6 @@ using System; -using System.Globalization; using System.IO; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Utils; namespace Contentstack.Management.Core.Services.Stack @@ -14,13 +13,13 @@ internal class StackCreateUpdateService : ContentstackService #region Internal internal StackCreateUpdateService( - JsonSerializer serializer, + JsonSerializerOptions serializerOptions, Core.Models.Stack stack, string name, string masterLocale = null, string description = null, string organizationUid = null) - : base(serializer, stack) + : base(serializerOptions, stack) { this.ResourcePath = "/stacks"; @@ -53,37 +52,33 @@ internal StackCreateUpdateService( public override void ContentBody() { - using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture)) + using var ms = new MemoryStream(); + using (var writer = new Utf8JsonWriter(ms)) { - JsonWriter writer = new JsonTextWriter(stringWriter); writer.WriteStartObject(); writer.WritePropertyName("stack"); writer.WriteStartObject(); if (!string.IsNullOrEmpty(_name)) { - writer.WritePropertyName("name"); - writer.WriteValue(_name); + writer.WriteString("name", _name); } if (!string.IsNullOrEmpty(_description)) { - writer.WritePropertyName("description"); - writer.WriteValue(_description); + writer.WriteString("description", _description); } switch (this.HttpMethod) { case "POST": - writer.WritePropertyName("master_locale"); - writer.WriteValue(_masterLocale); + writer.WriteString("master_locale", _masterLocale); break; default: break; } writer.WriteEndObject(); writer.WriteEndObject(); - - string snippet = stringWriter.ToString(); - this.ByteContent = System.Text.Encoding.UTF8.GetBytes(snippet); } + + this.ByteContent = ms.ToArray(); } #endregion } diff --git a/Contentstack.Management.Core/Services/Stack/StackSettingsService.cs b/Contentstack.Management.Core/Services/Stack/StackSettingsService.cs index 8855cc7..8955179 100644 --- a/Contentstack.Management.Core/Services/Stack/StackSettingsService.cs +++ b/Contentstack.Management.Core/Services/Stack/StackSettingsService.cs @@ -2,7 +2,7 @@ using System.Globalization; using System.IO; using Contentstack.Management.Core.Models; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Utils; namespace Contentstack.Management.Core.Services.Stack @@ -13,7 +13,7 @@ internal class StackSettingsService: ContentstackService private readonly StackSettings _settings; - internal StackSettingsService(JsonSerializer serializer, Core.Models.Stack stack, string method = "GET", StackSettings settings = null) : base(serializer, stack) + internal StackSettingsService(JsonSerializerOptions serializerOptions, Core.Models.Stack stack, string method = "GET", StackSettings settings = null) : base(serializerOptions, stack) { if (stack.APIKey == null) { @@ -29,7 +29,7 @@ public override void ContentBody() switch (HttpMethod) { case "POST": - string snippet = $"{{\"stack_settings\":{JsonConvert.SerializeObject(_settings)}}}"; + string snippet = $"{{\"stack_settings\":{JsonSerializer.Serialize(_settings, SerializerOptions)}}}"; ByteContent = System.Text.Encoding.UTF8.GetBytes(snippet); break; default: diff --git a/Contentstack.Management.Core/Services/User/ForgotPasswordService.cs b/Contentstack.Management.Core/Services/User/ForgotPasswordService.cs index e16f9f0..a87f697 100644 --- a/Contentstack.Management.Core/Services/User/ForgotPasswordService.cs +++ b/Contentstack.Management.Core/Services/User/ForgotPasswordService.cs @@ -1,7 +1,6 @@ using System; -using System.Globalization; using System.IO; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Utils; namespace Contentstack.Management.Core.Services.User @@ -10,7 +9,7 @@ internal class ForgotPasswordService : ContentstackService { private readonly string _email; - internal ForgotPasswordService(JsonSerializer serializer, string email): base (serializer) + internal ForgotPasswordService(JsonSerializerOptions serializerOptions, string email): base (serializerOptions) { if (string.IsNullOrEmpty(email)) { @@ -24,20 +23,18 @@ internal ForgotPasswordService(JsonSerializer serializer, string email): base (s public override void ContentBody() { - using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture)) + using var ms = new MemoryStream(); + using (var writer = new Utf8JsonWriter(ms)) { - JsonWriter writer = new JsonTextWriter(stringWriter); writer.WriteStartObject(); writer.WritePropertyName("user"); - writer.WriteStartObject(); - writer.WritePropertyName("email"); - writer.WriteValue(_email); - writer.WriteEndObject(); + writer.WriteStartObject(); + writer.WriteString("email", _email); + writer.WriteEndObject(); writer.WriteEndObject(); - - string snippet = stringWriter.ToString(); - this.ByteContent = System.Text.Encoding.UTF8.GetBytes(snippet); } + + this.ByteContent = ms.ToArray(); } } } diff --git a/Contentstack.Management.Core/Services/User/GetLoggedInUserService.cs b/Contentstack.Management.Core/Services/User/GetLoggedInUserService.cs index 5d76362..bf8a251 100644 --- a/Contentstack.Management.Core/Services/User/GetLoggedInUserService.cs +++ b/Contentstack.Management.Core/Services/User/GetLoggedInUserService.cs @@ -1,12 +1,12 @@ using System; using Contentstack.Management.Core.Queryable; -using Newtonsoft.Json; +using System.Text.Json; namespace Contentstack.Management.Core.Services.User { internal class GetLoggedInUserService: ContentstackService { - public GetLoggedInUserService(JsonSerializer serializer, ParameterCollection collection): base(serializer, collection: collection) + public GetLoggedInUserService(JsonSerializerOptions serializerOptions, ParameterCollection collection): base(serializerOptions, collection: collection) { this.ResourcePath = "user"; } diff --git a/Contentstack.Management.Core/Services/User/LoginService.cs b/Contentstack.Management.Core/Services/User/LoginService.cs index 977926e..006f85c 100644 --- a/Contentstack.Management.Core/Services/User/LoginService.cs +++ b/Contentstack.Management.Core/Services/User/LoginService.cs @@ -1,9 +1,8 @@ using System; using System.IO; using System.Net; -using Newtonsoft.Json; -using System.Globalization; -using Newtonsoft.Json.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; using OtpNet; using Contentstack.Management.Core.Http; using Contentstack.Management.Core.Utils; @@ -18,7 +17,7 @@ internal class LoginService : ContentstackService #endregion #region Constructor - internal LoginService(JsonSerializer serializer, ICredentials credentials, string token = null, string mfaSecret = null): base(serializer) + internal LoginService(JsonSerializerOptions serializerOptions, ICredentials credentials, string token = null, string mfaSecret = null): base(serializerOptions) { this.HttpMethod = "POST"; this.ResourcePath = "user-session"; @@ -46,44 +45,33 @@ internal LoginService(JsonSerializer serializer, ICredentials credentials, strin public override void ContentBody() { - using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture)) + var credential = _credentials as NetworkCredential; + using var ms = new MemoryStream(); + using (var writer = new Utf8JsonWriter(ms)) { - var credential = _credentials as NetworkCredential; - JsonWriter writer = new JsonTextWriter(stringWriter); writer.WriteStartObject(); writer.WritePropertyName("user"); writer.WriteStartObject(); - writer.WritePropertyName("email"); - writer.WriteValue(credential.UserName); - writer.WritePropertyName("password"); - writer.WriteValue(credential.Password); + writer.WriteString("email", credential.UserName); + writer.WriteString("password", credential.Password); if (_token != null) - { - writer.WritePropertyName("tfa_token"); - writer.WriteValue(_token); - } + writer.WriteString("tfa_token", _token); writer.WriteEndObject(); writer.WriteEndObject(); - - string snippet = stringWriter.ToString(); - this.ByteContent = System.Text.Encoding.UTF8.GetBytes(snippet); } + + this.ByteContent = ms.ToArray(); } public override void OnResponse(IResponse httpResponse, ContentstackClientOptions config) { if (httpResponse.IsSuccessStatusCode) { - JObject jObject = httpResponse.OpenJObjectResponse(); - var user = jObject.GetValue("user"); - if (user != null && user.GetType() == typeof(JObject)) + var root = httpResponse.OpenJsonObjectResponse(); + if (root.TryGetPropertyValue("user", out var userNode) && userNode is JsonObject userObj) { - JObject userObj = (JObject)user; - var authtoken = userObj.GetValue("authtoken"); - if (authtoken != null) - { - config.Authtoken = (string)authtoken; - } + if (userObj.TryGetPropertyValue("authtoken", out var at) && at != null) + config.Authtoken = at.GetValue(); } } diff --git a/Contentstack.Management.Core/Services/User/LogoutService.cs b/Contentstack.Management.Core/Services/User/LogoutService.cs index b5e003a..de97ded 100644 --- a/Contentstack.Management.Core/Services/User/LogoutService.cs +++ b/Contentstack.Management.Core/Services/User/LogoutService.cs @@ -1,5 +1,5 @@ using System; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Utils; namespace Contentstack.Management.Core.Services.User @@ -9,7 +9,7 @@ internal class LogoutService : ContentstackService private readonly string _authtoken; #region Constructor - public LogoutService(JsonSerializer serializer, string authtoken): base(serializer) + public LogoutService(JsonSerializerOptions serializerOptions, string authtoken): base(serializerOptions) { this.HttpMethod = "DELETE"; this.ResourcePath = "user-session"; diff --git a/Contentstack.Management.Core/Services/User/ResetPasswordService.cs b/Contentstack.Management.Core/Services/User/ResetPasswordService.cs index 799732a..4db1b4c 100644 --- a/Contentstack.Management.Core/Services/User/ResetPasswordService.cs +++ b/Contentstack.Management.Core/Services/User/ResetPasswordService.cs @@ -1,7 +1,6 @@ using System; -using System.Globalization; using System.IO; -using Newtonsoft.Json; +using System.Text.Json; using Contentstack.Management.Core.Utils; namespace Contentstack.Management.Core.Services.User @@ -12,7 +11,7 @@ internal class ResetPasswordService: ContentstackService private readonly string _password; private readonly string _confirmPassword; - internal ResetPasswordService(JsonSerializer serializer, string resetPasswordToken, string password, string confirmPassword) : base(serializer) + internal ResetPasswordService(JsonSerializerOptions serializerOptions, string resetPasswordToken, string password, string confirmPassword) : base(serializerOptions) { if (string.IsNullOrEmpty(resetPasswordToken)) { @@ -36,24 +35,20 @@ internal ResetPasswordService(JsonSerializer serializer, string resetPasswordTok public override void ContentBody() { - using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture)) + using var ms = new MemoryStream(); + using (var writer = new Utf8JsonWriter(ms)) { - JsonWriter writer = new JsonTextWriter(stringWriter); writer.WriteStartObject(); writer.WritePropertyName("user"); - writer.WriteStartObject(); - writer.WritePropertyName("reset_password_token"); - writer.WriteValue(_resetPasswordToken); - writer.WritePropertyName("password"); - writer.WriteValue(_password); - writer.WritePropertyName("password_confirmation"); - writer.WriteValue(_confirmPassword); - writer.WriteEndObject(); + writer.WriteStartObject(); + writer.WriteString("reset_password_token", _resetPasswordToken); + writer.WriteString("password", _password); + writer.WriteString("password_confirmation", _confirmPassword); + writer.WriteEndObject(); writer.WriteEndObject(); - - string snippet = stringWriter.ToString(); - this.ByteContent = System.Text.Encoding.UTF8.GetBytes(snippet); } + + this.ByteContent = ms.ToArray(); } } } diff --git a/Contentstack.Management.Core/Utils/FieldJsonConverter.cs b/Contentstack.Management.Core/Utils/FieldJsonConverter.cs index 2a76dd9..6d70e6a 100644 --- a/Contentstack.Management.Core/Utils/FieldJsonConverter.cs +++ b/Contentstack.Management.Core/Utils/FieldJsonConverter.cs @@ -1,7 +1,7 @@ using System; +using System.Text.Json; +using System.Text.Json.Serialization; using Contentstack.Management.Core.Models.Fields; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Contentstack.Management.Core.Utils { @@ -10,38 +10,38 @@ namespace Contentstack.Management.Core.Utils /// public class FieldJsonConverter : JsonConverter { - public override bool CanWrite => false; - - public override void WriteJson(JsonWriter writer, Field value, JsonSerializer serializer) - { - throw new NotSupportedException(); - } - - public override Field ReadJson(JsonReader reader, Type objectType, Field existingValue, bool hasExistingValue, JsonSerializer serializer) + public override Field Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonToken.Null) + if (reader.TokenType == JsonTokenType.Null) return null; - var jo = JObject.Load(reader); - var dataType = jo["data_type"]?.Value(); - var targetType = ResolveConcreteType(jo, dataType); - var field = (Field)Activator.CreateInstance(targetType); + using var doc = JsonDocument.ParseValue(ref reader); + var root = doc.RootElement; + var targetType = ResolveConcreteType(root); + var innerOpts = options.WithoutConverter(); + return (Field)JsonSerializer.Deserialize(root.GetRawText(), targetType, innerOpts); + } - using (var subReader = jo.CreateReader()) + public override void Write(Utf8JsonWriter writer, Field value, JsonSerializerOptions options) + { + if (value == null) { - serializer.Populate(subReader, field); + writer.WriteNullValue(); + return; } - return field; + var innerOpts = options.WithoutConverter(); + JsonSerializer.Serialize(writer, value, value.GetType(), innerOpts); } - private static Type ResolveConcreteType(JObject jo, string dataType) + private static Type ResolveConcreteType(JsonElement jo) { - // API returns extension-backed fields with data_type = extension's data type (e.g. "text"), not "extension". - var extensionUid = jo["extension_uid"]?.Value(); + var extensionUid = jo.TryGetProperty("extension_uid", out var ext) ? ext.GetString() : null; if (!string.IsNullOrEmpty(extensionUid)) return typeof(ExtensionField); + var dataType = jo.TryGetProperty("data_type", out var dt) ? dt.GetString() : null; + if (string.IsNullOrEmpty(dataType)) return typeof(Field); @@ -64,16 +64,22 @@ private static Type ResolveConcreteType(JObject jo, string dataType) case "isodate": return typeof(DateField); case "file": - var fm = jo["field_metadata"]; - if (jo["dimension"] != null || fm?["image"]?.Value() == true) + if (jo.TryGetProperty("field_metadata", out var fm)) + { + if (jo.TryGetProperty("dimension", out _) || + (fm.TryGetProperty("image", out var img) && img.ValueKind == JsonValueKind.True)) + return typeof(ImageField); + } + else if (jo.TryGetProperty("dimension", out _)) return typeof(ImageField); + return typeof(FileField); case "json": return typeof(JsonField); case "text": - if (jo["enum"] != null) + if (jo.TryGetProperty("enum", out _)) return typeof(SelectField); - var displayType = jo["display_type"]?.Value(); + var displayType = jo.TryGetProperty("display_type", out var dtp) ? dtp.GetString() : null; if (displayType == "dropdown" || displayType == "checkbox") return typeof(SelectField); return typeof(TextboxField); diff --git a/Contentstack.Management.Core/Utils/JsonSerializerOptionsExtensions.cs b/Contentstack.Management.Core/Utils/JsonSerializerOptionsExtensions.cs new file mode 100644 index 0000000..3712550 --- /dev/null +++ b/Contentstack.Management.Core/Utils/JsonSerializerOptionsExtensions.cs @@ -0,0 +1,28 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Contentstack.Management.Core.Utils +{ + internal static class JsonSerializerOptionsExtensions + { + /// + /// Clone options and remove the first converter of type to avoid re-entrancy in custom converters. + /// + public static JsonSerializerOptions WithoutConverter(this JsonSerializerOptions source) + where TConverter : JsonConverter + { + var o = new JsonSerializerOptions(source); + for (var i = o.Converters.Count - 1; i >= 0; i--) + { + if (o.Converters[i] is TConverter) + { + o.Converters.RemoveAt(i); + break; + } + } + + return o; + } + } +} \ No newline at end of file diff --git a/Contentstack.Management.Core/Utils/NodeJsonConverter.cs b/Contentstack.Management.Core/Utils/NodeJsonConverter.cs index aaa18ea..e69932b 100644 --- a/Contentstack.Management.Core/Utils/NodeJsonConverter.cs +++ b/Contentstack.Management.Core/Utils/NodeJsonConverter.cs @@ -1,40 +1,60 @@ using System; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; using Contentstack.Management.Core.Models; namespace Contentstack.Management.Core.Utils { public class NodeJsonConverter : JsonConverter { - public override Node ReadJson(JsonReader reader, Type objectType, Node existingValue, bool hasExistingValue, JsonSerializer serializer) + public override Node Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - Node node = null; - JObject jObject = JObject.Load(reader); - if (jObject["type"] == null) - { - node = new TextNode(); - node.type = "text"; - } - else + using var doc = JsonDocument.ParseValue(ref reader); + var root = doc.RootElement; + var raw = root.GetRawText(); + + var missingOrNullType = + !root.TryGetProperty("type", out var typeProp) || + typeProp.ValueKind == JsonValueKind.Null; + + if (missingOrNullType) { - node = new Node(); + var innerOpts = options.WithoutConverter(); + var textNode = JsonSerializer.Deserialize(raw, innerOpts) ?? new TextNode(); + if (string.IsNullOrEmpty(textNode.type)) + textNode.type = "text"; + return textNode; } - serializer.Populate(jObject.CreateReader(), node); - return node; + + var nodeOpts = options.WithoutConverter(); + return JsonSerializer.Deserialize(raw, nodeOpts) ?? new Node(); } - public override void WriteJson(JsonWriter writer, Node value, JsonSerializer serializer) + public override void Write(Utf8JsonWriter writer, Node value, JsonSerializerOptions options) { - writer.WriteStartObject(); + if (value == null) + { + writer.WriteNullValue(); + return; + } - writer.WritePropertyName("type"); - writer.WriteValue(value.type); + if (value is TextNode textNode) + { + new TextNodeJsonConverter().Write(writer, textNode, options); + return; + } + + writer.WriteStartObject(); + + if (!string.IsNullOrEmpty(value.type)) + { + writer.WriteString("type", value.type); + } if (value.attrs != null) { writer.WritePropertyName("attrs"); - serializer.Serialize(writer, value.attrs); + JsonSerializer.Serialize(writer, value.attrs, options); } if (value.children != null) @@ -43,7 +63,7 @@ public override void WriteJson(JsonWriter writer, Node value, JsonSerializer ser writer.WriteStartArray(); foreach (var child in value.children) { - serializer.Serialize(writer, child); + JsonSerializer.Serialize(writer, child, options); } writer.WriteEndArray(); } diff --git a/Contentstack.Management.Core/Utils/TextNodeJsonConverter.cs b/Contentstack.Management.Core/Utils/TextNodeJsonConverter.cs index ce75361..6ac82f7 100644 --- a/Contentstack.Management.Core/Utils/TextNodeJsonConverter.cs +++ b/Contentstack.Management.Core/Utils/TextNodeJsonConverter.cs @@ -1,32 +1,33 @@ using System; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; using Contentstack.Management.Core.Models; -using Microsoft.Extensions.Options; namespace Contentstack.Management.Core.Utils { public class TextNodeJsonConverter : JsonConverter { - public override TextNode ReadJson(JsonReader reader, Type objectType, TextNode existingValue, bool hasExistingValue, JsonSerializer serializer) + public override TextNode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - JObject jObject = JObject.Load(reader); - - TextNode txtnode = new TextNode(); - - serializer.Populate(jObject.CreateReader(), txtnode); - - return txtnode; + using var doc = JsonDocument.ParseValue(ref reader); + var innerOpts = options.WithoutConverter(); + return JsonSerializer.Deserialize(doc.RootElement.GetRawText(), innerOpts) ?? new TextNode(); } - public override void WriteJson(JsonWriter writer, TextNode value, JsonSerializer serializer) + public override void Write(Utf8JsonWriter writer, TextNode value, JsonSerializerOptions options) { + if (value == null) + { + writer.WriteNullValue(); + return; + } + writer.WriteStartObject(); if (value.attrs != null) { writer.WritePropertyName("attrs"); - serializer.Serialize(writer, value.attrs); + JsonSerializer.Serialize(writer, value.attrs, options); } if (value.children != null) @@ -35,7 +36,7 @@ public override void WriteJson(JsonWriter writer, TextNode value, JsonSerializer writer.WriteStartArray(); foreach (var child in value.children) { - serializer.Serialize(writer, child); + JsonSerializer.Serialize(writer, child, options); } writer.WriteEndArray(); } @@ -43,47 +44,47 @@ public override void WriteJson(JsonWriter writer, TextNode value, JsonSerializer if (value.bold) { writer.WritePropertyName("bold"); - writer.WriteValue(value.bold); + writer.WriteBooleanValue(value.bold); } if (value.italic) { writer.WritePropertyName("italic"); - writer.WriteValue(value.italic); + writer.WriteBooleanValue(value.italic); } if (value.underline) { writer.WritePropertyName("underline"); - writer.WriteValue(value.underline); + writer.WriteBooleanValue(value.underline); } if (value.strikethrough) { writer.WritePropertyName("strikethrough"); - writer.WriteValue(value.strikethrough); + writer.WriteBooleanValue(value.strikethrough); } if (value.inlineCode) { writer.WritePropertyName("inlineCode"); - writer.WriteValue(value.inlineCode); + writer.WriteBooleanValue(value.inlineCode); } if (value.subscript) { writer.WritePropertyName("subscript"); - writer.WriteValue(value.subscript); + writer.WriteBooleanValue(value.subscript); } if (value.superscript) { writer.WritePropertyName("superscript"); - writer.WriteValue(value.superscript); + writer.WriteBooleanValue(value.superscript); } if (value.@break) { writer.WritePropertyName("break"); - writer.WriteValue(value.@break); + writer.WriteBooleanValue(value.@break); } if (!string.IsNullOrEmpty(value.text)) { writer.WritePropertyName("text"); - writer.WriteValue(value.text); + writer.WriteStringValue(value.text); } writer.WriteEndObject(); diff --git a/Contentstack.Management.Core/contentstack.management.core.csproj b/Contentstack.Management.Core/contentstack.management.core.csproj index f422b69..acefc32 100644 --- a/Contentstack.Management.Core/contentstack.management.core.csproj +++ b/Contentstack.Management.Core/contentstack.management.core.csproj @@ -8,7 +8,7 @@ netstandard2.0 - 8.0 + 9.0 enable Contentstack Management Contentstack @@ -73,6 +73,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Directory.Build.props b/Directory.Build.props index 355f623..02afb64 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - 0.10.0 + 1.0.0-beta.1