From 60f9e571e5af5a3d4484294d2cba3e43536dd28c Mon Sep 17 00:00:00 2001 From: Robert Linde Date: Wed, 2 Oct 2024 07:52:35 +0200 Subject: [PATCH] Contentful client tweaks (#351) * Avoid waiting for complete response, if we are just checking if for success status code. Avoid evaluating OS & Version for every request. Avoid a possible MemoryStream leak. Other minor tweaks * Dispose responses & requests, pass cancellationToken & avoid an array allocation * Dispose cloned request, add sealed & readonly * Avoid deserializing into a string by deserializing directly from the response stream. Then deserialization can start immediately instead of waiting for the entire response. Reuse JsonSerializerSettings. Avoid async Task methods where it adds no value. * Use HTTP/2 * Allow HTTP response connection * Update package and dependency --------- Co-authored-by: Henrik Gedionsen --- .../Contentful.AspNetCore.csproj | 10 +- .../IServiceCollectionExtensions.cs | 16 +- .../Configuration/ContentfulOptions.cs | 6 + .../Configuration/ExtensionJsonConverter.cs | 23 +- Contentful.Core/Contentful.Core.csproj | 2 +- Contentful.Core/ContentfulClient.cs | 73 +- Contentful.Core/ContentfulClientBase.cs | 62 +- Contentful.Core/ContentfulManagementClient.cs | 750 ++++++------------ .../Extensions/JsonConversionExtensions.cs | 70 +- .../Models/Management/IFieldValidation.cs | 9 +- Contentful.Core/Search/SelectVisitor.cs | 4 +- 11 files changed, 393 insertions(+), 632 deletions(-) diff --git a/Contentful.AspNetCore/Contentful.AspNetCore.csproj b/Contentful.AspNetCore/Contentful.AspNetCore.csproj index 4593b09..4931331 100644 --- a/Contentful.AspNetCore/Contentful.AspNetCore.csproj +++ b/Contentful.AspNetCore/Contentful.AspNetCore.csproj @@ -3,7 +3,7 @@ Official .NET SDK for the Contentful Content Delivery and Management API for ASP.NET core. contentful.aspnetcore en-US - 8.1.0 + 8.2.0 netstandard2.0 Contentful Contentful GmbH. @@ -13,10 +13,10 @@ https://github.com/contentful/contentful.net MIT git - 8.1.0 - 8.1.0.0 + 8.2.0 + 8.2.0.0 https://github.com/contentful/contentful.net - 8.1.0.0 + 8.2.0.0 bin\Release\netstandard1.5\Contentful.AspNetCore.xml @@ -25,7 +25,7 @@ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - + diff --git a/Contentful.AspNetCore/IServiceCollectionExtensions.cs b/Contentful.AspNetCore/IServiceCollectionExtensions.cs index 3b390db..26179a4 100644 --- a/Contentful.AspNetCore/IServiceCollectionExtensions.cs +++ b/Contentful.AspNetCore/IServiceCollectionExtensions.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Net; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Contentful.Core.Configuration; @@ -8,7 +6,6 @@ using System.Net.Http; using Contentful.Core; using Microsoft.Extensions.Options; -using Microsoft.Extensions.Http; using Contentful.Core.Models; namespace Contentful.AspNetCore @@ -31,7 +28,16 @@ public static IServiceCollection AddContentful(this IServiceCollection services, services.AddOptions(); services.Configure(configuration.GetSection("ContentfulOptions")); services.TryAddSingleton(); - services.AddHttpClient(HttpClientName); + services.AddHttpClient(HttpClientName).ConfigurePrimaryHttpMessageHandler(sp => + { + var options = sp.GetService>().Value; + var handler = new HttpClientHandler(); + if (options.AllowHttpResponseCompression && handler.SupportsAutomaticDecompression) + { + handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + } + return handler; + }); services.TryAddTransient((sp) => { var options = sp.GetService>().Value; var factory = sp.GetService(); diff --git a/Contentful.Core/Configuration/ContentfulOptions.cs b/Contentful.Core/Configuration/ContentfulOptions.cs index ec7371b..b893e1c 100644 --- a/Contentful.Core/Configuration/ContentfulOptions.cs +++ b/Contentful.Core/Configuration/ContentfulOptions.cs @@ -56,5 +56,11 @@ public class ContentfulOptions /// Default is "https://cdn.contentful.com/spaces/". /// public string BaseUrl { get; set; } = "https://cdn.contentful.com/spaces/"; + + /// + /// Whether to use HTTP compression for responses. Only disable if you are hosting in the same datacenter as contentful + /// Default is true + /// + public bool AllowHttpResponseCompression { get; set; } = true; } } diff --git a/Contentful.Core/Configuration/ExtensionJsonConverter.cs b/Contentful.Core/Configuration/ExtensionJsonConverter.cs index 27e0958..86d693a 100644 --- a/Contentful.Core/Configuration/ExtensionJsonConverter.cs +++ b/Contentful.Core/Configuration/ExtensionJsonConverter.cs @@ -4,9 +4,7 @@ using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using System; -using System.Collections.Generic; using System.Linq; -using System.Text; namespace Contentful.Core.Configuration { @@ -15,6 +13,17 @@ namespace Contentful.Core.Configuration /// public class ExtensionJsonConverter : JsonConverter { + private static readonly JsonSerializerSettings JsonSerializerSettings = new() + { + ContractResolver = new CamelCasePropertyNamesContractResolver + { + NamingStrategy = + { + OverrideSpecifiedNames = false + } + }, + }; + /// /// Determines whether this instance can convert the specified object type. /// @@ -75,15 +84,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s extension }; - var resolver = new CamelCasePropertyNamesContractResolver(); - resolver.NamingStrategy.OverrideSpecifiedNames = false; - - var settings = new JsonSerializerSettings - { - ContractResolver = resolver, - }; - - var jObject = JObject.FromObject(extensionStructure, JsonSerializer.Create(settings)); + var jObject = JObject.FromObject(extensionStructure, JsonSerializer.Create(JsonSerializerSettings)); serializer.Serialize(writer, jObject); } diff --git a/Contentful.Core/Contentful.Core.csproj b/Contentful.Core/Contentful.Core.csproj index 24ea2ac..ab9c511 100644 --- a/Contentful.Core/Contentful.Core.csproj +++ b/Contentful.Core/Contentful.Core.csproj @@ -4,7 +4,7 @@ contentful.csharp contentful.net en-US - 8.1.0 + 8.2.0 netstandard2.0 Contentful Contentful GmbH. diff --git a/Contentful.Core/ContentfulClient.cs b/Contentful.Core/ContentfulClient.cs index e1f82fd..9605693 100644 --- a/Contentful.Core/ContentfulClient.cs +++ b/Contentful.Core/ContentfulClient.cs @@ -109,9 +109,9 @@ public ContentfulClient(HttpClient httpClient, string deliveryApiKey, string pre /// The response from the API serialized into /// There was an error when communicating with the Contentful API. /// The entryId parameter was null or empty. - public async Task GetEntry(string entryId, QueryBuilder queryBuilder, CancellationToken cancellationToken = default) + public Task GetEntry(string entryId, QueryBuilder queryBuilder, CancellationToken cancellationToken = default) { - return await GetEntry(entryId, queryBuilder?.Build(), cancellationToken).ConfigureAwait(false); + return GetEntry(entryId, queryBuilder?.Build(), cancellationToken); } /// @@ -134,14 +134,14 @@ public async Task> GetEntry(string entryId, string etag, throw new ArgumentException(nameof(entryId)); } - var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}entries/{entryId}{queryString}", etag, cancellationToken, CrossSpaceResolutionSettings).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}entries/{entryId}{queryString}", etag, cancellationToken, CrossSpaceResolutionSettings).ConfigureAwait(false); if(!string.IsNullOrEmpty(etag) && res.Headers?.ETag?.Tag == etag) { return new ContentfulResult(res.Headers?.ETag?.Tag, default(T)); } - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var json = await res.GetJObjectFromResponse().ConfigureAwait(false); JToken entry; @@ -211,28 +211,28 @@ public async Task> GetEntriesByType(string contentTyp /// The optional cancellation token to cancel the operation. /// A of items. /// There was an error when communicating with the Contentful API. - public async Task> GetEntries(QueryBuilder queryBuilder, CancellationToken cancellationToken = default) + public Task> GetEntries(QueryBuilder queryBuilder, CancellationToken cancellationToken = default) { - return await GetEntries(queryBuilder?.Build(), cancellationToken).ConfigureAwait(false); + return GetEntries(queryBuilder?.Build(), cancellationToken); } public async Task GetEntriesRaw(string queryString = null, CancellationToken cancellationToken = default) { - var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}entries{queryString}", null, cancellationToken, CrossSpaceResolutionSettings).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}entries{queryString}", null, cancellationToken, CrossSpaceResolutionSettings).ConfigureAwait(false); var resultString = await res.Content.ReadAsStringAsync().ConfigureAwait(false); return resultString; } public async Task>> GetEntries(string etag, string queryString = null, CancellationToken cancellationToken = default) { - var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}entries{queryString}", etag, cancellationToken, CrossSpaceResolutionSettings).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}entries{queryString}", etag, cancellationToken, CrossSpaceResolutionSettings).ConfigureAwait(false); if (!string.IsNullOrEmpty(etag) && res.Headers?.ETag.Tag == etag) { return new ContentfulResult>(res.Headers?.ETag?.Tag, null); } - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var json = await res.GetJObjectFromResponse().ConfigureAwait(false); ReplaceMetaData(json); @@ -475,9 +475,9 @@ private void ResolveLinks(JObject json, JObject entryToken, ISet process /// The response from the API serialized into an /// There was an error when communicating with the Contentful API. /// The assetId parameter was null or emtpy. - public async Task GetAsset(string assetId, QueryBuilder queryBuilder, CancellationToken cancellationToken = default) + public Task GetAsset(string assetId, QueryBuilder queryBuilder, CancellationToken cancellationToken = default) { - return await GetAsset(assetId, queryBuilder?.Build(), cancellationToken); + return GetAsset(assetId, queryBuilder?.Build(), cancellationToken); } /// @@ -496,15 +496,14 @@ public async Task> GetAsset(string assetId, string etag, throw new ArgumentException(nameof(assetId)); } - var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}assets/{assetId}{queryString}", etag, cancellationToken, null).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}assets/{assetId}{queryString}", etag, cancellationToken, null).ConfigureAwait(false); if (!string.IsNullOrEmpty(etag) && res.Headers?.ETag?.Tag == etag) { return new ContentfulResult(res.Headers?.ETag?.Tag, null); } - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var asset = jsonObject.ToObject(Serializer); + var asset = await res.GetObjectFromResponse(Serializer).ConfigureAwait(false); return new ContentfulResult(res.Headers?.ETag?.Tag, asset); } @@ -532,9 +531,9 @@ public async Task GetAsset(string assetId, string queryString = null, Can /// The optional cancellation token to cancel the operation. /// A of . /// There was an error when communicating with the Contentful API. - public async Task> GetAssets(QueryBuilder queryBuilder, CancellationToken cancellationToken = default) + public Task> GetAssets(QueryBuilder queryBuilder, CancellationToken cancellationToken = default) { - return await GetAssets(queryBuilder?.Build(), cancellationToken).ConfigureAwait(false); + return GetAssets(queryBuilder?.Build(), cancellationToken); } /// @@ -547,14 +546,14 @@ public async Task> GetAssets(QueryBuilder que /// There was an error when communicating with the Contentful API. public async Task>> GetAssets(string etag, string queryString = null, CancellationToken cancellationToken = default) { - var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}assets/{queryString}", etag, cancellationToken, null).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}assets/{queryString}", etag, cancellationToken, null).ConfigureAwait(false); if (!string.IsNullOrEmpty(etag) && res.Headers?.ETag?.Tag == etag) { return new ContentfulResult>(res.Headers?.ETag?.Tag, null); } - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await res.GetJObjectFromResponse().ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var assets = jsonObject.SelectTokens("$.items[*]").Select(c => c.ToObject(Serializer)); ; collection.Items = assets; @@ -599,8 +598,7 @@ public async Task CreateEmbargoedAssetKey(DateTimeOffset time //note that unlike some other api methods, the asset embargo key always requires an environment id. var res = await Post($"{BaseUrl}{_options.SpaceId}/{(EnvironmentsBase == string.Empty ? "environments/master/" : EnvironmentsBase)}asset_keys", new { expiresAt }, cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var assetKey = jsonObject.ToObject(Serializer); + var assetKey = await res.GetObjectFromResponse(Serializer).ConfigureAwait(false); assetKey.ExpiresAtUtc = timeOffset.UtcDateTime; return assetKey; } @@ -613,15 +611,14 @@ public async Task CreateEmbargoedAssetKey(DateTimeOffset time /// There was an error when communicating with the Contentful API. public async Task> GetSpace(string etag, CancellationToken cancellationToken = default) { - var res = await Get($"{BaseUrl}{_options.SpaceId}", etag, cancellationToken, null).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}", etag, cancellationToken, null).ConfigureAwait(false); if (!string.IsNullOrEmpty(etag) && res.Headers?.ETag?.Tag == etag) { return new ContentfulResult(res.Headers?.ETag?.Tag, null); } - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var space = jsonObject.ToObject(Serializer); + var space = await res.GetObjectFromResponse(Serializer).ConfigureAwait(false); return new ContentfulResult(res.Headers?.ETag?.Tag, space); } @@ -655,15 +652,14 @@ public async Task> GetContentType(string etag, str throw new ArgumentException(nameof(contentTypeId)); } - var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}", etag, cancellationToken, null).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}", etag, cancellationToken, null).ConfigureAwait(false); if (!string.IsNullOrEmpty(etag) && res.Headers?.ETag?.Tag == etag) { return new ContentfulResult(res.Headers?.ETag?.Tag, null); } - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var contentType = jsonObject.ToObject(Serializer); + var contentType = await res.GetObjectFromResponse(Serializer).ConfigureAwait(false); return new ContentfulResult(res.Headers?.ETag?.Tag, contentType); } @@ -675,9 +671,9 @@ public async Task> GetContentType(string etag, str /// An of . public async Task> GetTags(string queryString = "", CancellationToken cancellationToken = default) { - var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}tags/{queryString}", null, cancellationToken, null).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}tags/{queryString}", null, cancellationToken, null).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await res.GetJObjectFromResponse().ConfigureAwait(false); var tags = jsonObject.SelectTokens("$..items[*]").Select(t => t.ToObject(Serializer)); return tags; @@ -696,10 +692,9 @@ public async Task GetTag(string tagId, CancellationToken cancellatio throw new ArgumentException(nameof(tagId)); } - var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}tags/{tagId}", null, cancellationToken, null).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}tags/{tagId}", null, cancellationToken, null).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var tag = jsonObject.ToObject(Serializer); + var tag = await res.GetObjectFromResponse(Serializer).ConfigureAwait(false); return tag; } @@ -724,9 +719,9 @@ public async Task GetContentType(string contentTypeId, Cancellation /// /// The optional cancellation token to cancel the operation. /// An of . - public async Task> GetContentTypes(CancellationToken cancellationToken = default) + public Task> GetContentTypes(CancellationToken cancellationToken = default) { - return await GetContentTypes(null, cancellationToken); + return GetContentTypes(null, cancellationToken); } /// @@ -737,14 +732,14 @@ public async Task> GetContentTypes(CancellationToken ca /// An of . public async Task>> GetContentTypes(string etag, string queryString, CancellationToken cancellationToken = default) { - var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}content_types/{queryString}", etag, cancellationToken, null).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}content_types/{queryString}", etag, cancellationToken, null).ConfigureAwait(false); if (!string.IsNullOrEmpty(etag) && res.Headers?.ETag?.Tag == etag) { return new ContentfulResult>(res.Headers?.ETag?.Tag, null); } - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await res.GetJObjectFromResponse().ConfigureAwait(false); var contentTypes = jsonObject.SelectTokens("$..items[*]").Select(t => t.ToObject(Serializer)); return new ContentfulResult>(res.Headers?.ETag?.Tag, contentTypes); @@ -770,14 +765,14 @@ public async Task> GetContentTypes(string queryString, /// An of . public async Task>> GetLocales(string etag, CancellationToken cancellationToken = default) { - var res = await Get($"{BaseUrl}{_options.SpaceId}/{(string.IsNullOrEmpty(EnvironmentsBase) ? "environments/master/" : EnvironmentsBase)}locales/", etag, cancellationToken, null).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{(string.IsNullOrEmpty(EnvironmentsBase) ? "environments/master/" : EnvironmentsBase)}locales/", etag, cancellationToken, null).ConfigureAwait(false); if (!string.IsNullOrEmpty(etag) && res.Headers?.ETag?.Tag == etag) { return new ContentfulResult> (res.Headers?.ETag?.Tag, null); } - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await res.GetJObjectFromResponse().ConfigureAwait(false); var locales = jsonObject.SelectTokens("$..items[*]").Select(t => t.ToObject(Serializer)); return new ContentfulResult>(res.Headers?.ETag?.Tag, locales); @@ -815,7 +810,7 @@ public async Task SyncInitial(SyncType syncType = SyncType.All, stri var query = BuildSyncQuery(syncType, contentTypeId, true, limit: limit); - var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}sync{query}", "", cancellationToken, null).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}sync{query}", "", cancellationToken, null).ConfigureAwait(false); var syncResult = ParseSyncResult(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); @@ -842,7 +837,7 @@ public async Task SyncNextResult(string nextSyncOrPageUrl, Cancellat var query = BuildSyncQuery(syncToken: syncToken); - var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}sync{query}", "", cancellationToken, null).ConfigureAwait(false); + using var res = await Get($"{BaseUrl}{_options.SpaceId}/{EnvironmentsBase}sync{query}", "", cancellationToken, null).ConfigureAwait(false); var syncResult = ParseSyncResult(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); diff --git a/Contentful.Core/ContentfulClientBase.cs b/Contentful.Core/ContentfulClientBase.cs index 3f00a8c..a8b83c8 100644 --- a/Contentful.Core/ContentfulClientBase.cs +++ b/Contentful.Core/ContentfulClientBase.cs @@ -10,9 +10,9 @@ using System.Net.Http; using System.Reflection; using System.Runtime.InteropServices; -using System.Text; using System.Threading; using System.Threading.Tasks; +using Contentful.Core.Extensions; namespace Contentful.Core { @@ -21,6 +21,9 @@ namespace Contentful.Core /// public abstract class ContentfulClientBase { + private static readonly string InformationalVersion = typeof(ContentfulClientBase).GetTypeInfo().Assembly.GetCustomAttribute() + .InformationalVersion; + /// /// The HttpClient used for API calls. /// @@ -43,12 +46,12 @@ public abstract class ContentfulClientBase /// /// Returns the current version of the package. /// - public string Version => typeof(ContentfulClientBase).GetTypeInfo().Assembly.GetCustomAttribute() - .InformationalVersion; + public string Version => InformationalVersion; - private string Os => IsWindows ? "Windows" : IsMacOS ? "macOS" : "Linux"; + private static readonly string Os = IsWindows ? "Windows" : IsMacOS ? "macOS" : "Linux"; + private static readonly Version HttpVersion2 = new(2,0); - private string Platform => ".net"; + private const string Platform = ".net"; private static bool IsWindows { @@ -105,16 +108,14 @@ protected async Task CreateExceptionForFailedRequest(HttpResponseMessage res) message += errorDetails.Errors?.ToString(); } - IEnumerable headers = new List(); - - if(statusCode == 429 && res.Headers.TryGetValues("X-Contentful-RateLimit-Reset", out headers)) + if (statusCode == 429 && res.Headers.TryGetValues("X-Contentful-RateLimit-Reset", out var headers)) { var rateLimitException = new ContentfulRateLimitException(message) { RequestId = jsonError.SelectToken("$.requestId")?.ToString(), ErrorDetails = errorDetails, SystemProperties = sys, - SecondsUntilNextRequest = headers.FirstOrDefault() == null ? 0 : int.Parse(headers.FirstOrDefault()) + SecondsUntilNextRequest = int.TryParse(headers.FirstOrDefault(), out var rateLimitReset) ? rateLimitReset: 0 }; throw rateLimitException; @@ -141,7 +142,7 @@ protected async Task CreateExceptionForFailedRequest(HttpResponseMessage res) throw ex; } - private string GetGenericErrorMessageForStatusCode(int statusCode, string id) + private static string GetGenericErrorMessageForStatusCode(int statusCode, string id) { if(statusCode == 400) { @@ -222,8 +223,9 @@ private string GetGenericErrorMessageForStatusCode(int statusCode, string id) protected async Task SendHttpRequest(string url, HttpMethod method, string authToken, CancellationToken cancellationToken, HttpContent content = null, int? version = null, string contentTypeId = null, string organisationId = null, List>> additionalHeaders = null) { - var httpRequestMessage = new HttpRequestMessage() + using var httpRequestMessage = new HttpRequestMessage { + Version = HttpVersion2, RequestUri = new Uri(url), Method = method }; @@ -258,7 +260,7 @@ protected async Task SendHttpRequest(string url, HttpMethod private async Task SendHttpRequest(HttpRequestMessage request, CancellationToken cancellationToken) { - var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); + var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); response = await EnsureSuccessfulResult(response); @@ -272,16 +274,32 @@ private async Task SendHttpRequest(HttpRequestMessage reque /// The message to add the header to. protected void AddVersionHeader(int? version, HttpRequestMessage message) { - if (message.Headers.Contains("X-Contentful-Version")) - { - message.Headers.Remove("X-Contentful-Version"); - } + message.Headers.Remove("X-Contentful-Version"); if (version.HasValue) { message.Headers.Add("X-Contentful-Version", version.ToString()); } } + /// Returns an object of type T from the response, if the response is successful + /// The response to deserialize + /// The type that should be returned + /// The deserialized object + protected async Task GetObjectFromResponse(HttpResponseMessage response) + { + await EnsureSuccessfulResult(response).ConfigureAwait(false); + return await response.GetObjectFromResponse(Serializer).ConfigureAwait(false); + } + + /// Returns a JObject from the response, if the response is successful + /// The response to deserialize + /// The deserialized JObject + protected async Task GetJObjectFromResponse(HttpResponseMessage response) + { + await EnsureSuccessfulResult(response).ConfigureAwait(false); + return await response.GetJObjectFromResponse().ConfigureAwait(false); + } + /// /// Ensures an HttpResponse is successful. /// @@ -309,9 +327,9 @@ protected async Task EnsureSuccessfulResult(HttpResponseMes await Task.Delay(ex.SecondsUntilNextRequest * 1000).ConfigureAwait(false); } - var clonedMessage = await CloneHttpRequest(response.RequestMessage); + using var clonedMessage = await CloneHttpRequest(response.RequestMessage); - response = await _httpClient.SendAsync(clonedMessage).ConfigureAwait(false); + response = await _httpClient.SendAsync(clonedMessage, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false); if (response.IsSuccessStatusCode) { @@ -326,14 +344,14 @@ protected async Task EnsureSuccessfulResult(HttpResponseMes return response; } - private async Task CloneHttpRequest(HttpRequestMessage message) + private static async Task CloneHttpRequest(HttpRequestMessage message) { var clone = new HttpRequestMessage(message.Method, message.RequestUri); - + clone.Version = message.Version; // Copy the request's content (via a MemoryStream) into the cloned object - var ms = new MemoryStream(); if (message.Content != null) { + var ms = new MemoryStream(); await message.Content.CopyToAsync(ms).ConfigureAwait(false); ms.Position = 0; clone.Content = new StreamContent(ms); @@ -349,7 +367,7 @@ private async Task CloneHttpRequest(HttpRequestMessage messa return clone; } - protected void ReplaceMetaData(JObject jsonObject) + protected static void ReplaceMetaData(JObject jsonObject) { foreach (var item in jsonObject.SelectTokens("$.items[*]").OfType()) { diff --git a/Contentful.Core/ContentfulManagementClient.cs b/Contentful.Core/ContentfulManagementClient.cs index f4b8dea..0cf228c 100644 --- a/Contentful.Core/ContentfulManagementClient.cs +++ b/Contentful.Core/ContentfulManagementClient.cs @@ -4,9 +4,7 @@ using Contentful.Core.Models; using Contentful.Core.Models.Management; using Contentful.Core.Search; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.Linq; @@ -74,13 +72,9 @@ public ContentfulManagementClient(HttpClient httpClient, string managementApiKey /// The created public async Task CreateSpace(string name, string defaultLocale, string organisation = null, CancellationToken cancellationToken = default) { - var res = await PostAsync(_baseUrl, ConvertObjectToJsonStringContent(new { name, defaultLocale }), cancellationToken, null, organisationId: organisation).ConfigureAwait(false); + using var res = await PostAsync(_baseUrl, ConvertObjectToJsonStringContent(new { name, defaultLocale }), cancellationToken, null, organisationId: organisation).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return json.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -90,9 +84,9 @@ public async Task CreateSpace(string name, string defaultLocale, string o /// The organisation to update a space for. Not required if the account belongs to only one organisation. /// The optional cancellation token to cancel the operation. /// The updated - public async Task UpdateSpaceName(Space space, string organisation = null, CancellationToken cancellationToken = default) + public Task UpdateSpaceName(Space space, string organisation = null, CancellationToken cancellationToken = default) { - return await UpdateSpaceName(space.SystemProperties.Id, space.Name, space.SystemProperties.Version ?? 1, organisation, cancellationToken).ConfigureAwait(false); + return UpdateSpaceName(space.SystemProperties.Id, space.Name, space.SystemProperties.Version ?? 1, organisation, cancellationToken); } /// @@ -106,13 +100,9 @@ public async Task UpdateSpaceName(Space space, string organisation = null /// The updated public async Task UpdateSpaceName(string id, string name, int version, string organisation = null, CancellationToken cancellationToken = default) { - var res = await PutAsync($"{_baseUrl}{id}", ConvertObjectToJsonStringContent(new { name }), cancellationToken, version, organisationId: organisation).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await PutAsync($"{_baseUrl}{id}", ConvertObjectToJsonStringContent(new { name }), cancellationToken, version, organisationId: organisation).ConfigureAwait(false); - return json.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -123,13 +113,9 @@ public async Task UpdateSpaceName(string id, string name, int version, st /// The public async Task GetSpace(string id, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{id}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{id}", cancellationToken).ConfigureAwait(false); - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return json.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -139,11 +125,9 @@ public async Task GetSpace(string id, CancellationToken cancellationToken /// An of . public async Task> GetSpaces(CancellationToken cancellationToken = default) { - var res = await GetAsync(_baseUrl, cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync(_baseUrl, cancellationToken).ConfigureAwait(false); - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var json = await GetJObjectFromResponse(res).ConfigureAwait(false); return json.SelectTokens("$..items[*]").Select(t => t.ToObject(Serializer)); } @@ -156,7 +140,7 @@ public async Task> GetSpaces(CancellationToken cancellationTo /// public async Task DeleteSpace(string id, CancellationToken cancellationToken = default) { - var res = await DeleteAsync($"{_baseUrl}{id}", cancellationToken).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{id}", cancellationToken).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -167,9 +151,9 @@ public async Task DeleteSpace(string id, CancellationToken cancellationToken = d /// The id of the space to get the content types of. Will default to the one set when creating the client. /// The optional cancellation token to cancel the operation. /// An of . - public async Task> GetContentTypes(string spaceId = null, CancellationToken cancellationToken = default) + public Task> GetContentTypes(string spaceId = null, CancellationToken cancellationToken = default) { - return await GetContentTypes(null, spaceId, cancellationToken); + return GetContentTypes(null, spaceId, cancellationToken); } /// @@ -181,11 +165,9 @@ public async Task> GetContentTypes(string spaceId = nul /// An of . public async Task> GetContentTypes(string queryString, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{queryString}", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{queryString}", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var json = await GetJObjectFromResponse(res).ConfigureAwait(false); return json.SelectTokens("$..items[*]").Select(t => t.ToObject(Serializer)); } @@ -215,15 +197,11 @@ public async Task CreateOrUpdateContentType(ContentType contentType Metadata = contentType.Metadata, Name = contentType.Name, }; - var res = await PutAsync(baseUrl, + using var res = await PutAsync(baseUrl, ConvertObjectToJsonStringContent(clone), cancellationToken, version).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return json.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -242,14 +220,9 @@ public async Task GetContentType(string contentTypeId, string space throw new ArgumentException(nameof(contentTypeId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var contentType = jsonObject.ToObject(Serializer); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}", cancellationToken).ConfigureAwait(false); - return contentType; + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -268,7 +241,7 @@ public async Task DeleteContentType(string contentTypeId, string spaceId = null, throw new ArgumentException(nameof(contentTypeId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}", cancellationToken).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}", cancellationToken).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -290,14 +263,9 @@ public async Task ActivateContentType(string contentTypeId, int ver throw new ArgumentException(nameof(contentTypeId)); } - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/published", null, cancellationToken, version).ConfigureAwait(false); + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/published", null, cancellationToken, version).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var contentType = jsonObject.ToObject(Serializer); - - return contentType; + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -316,7 +284,7 @@ public async Task DeactivateContentType(string contentTypeId, string spaceId = n throw new ArgumentException(nameof(contentTypeId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/published", cancellationToken).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/published", cancellationToken).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -327,9 +295,9 @@ public async Task DeactivateContentType(string contentTypeId, string spaceId = n /// The id of the space to get the activated content types of. Will default to the one set when creating the client. /// The optional cancellation token to cancel the operation. /// An of . - public async Task> GetActivatedContentTypes(string spaceId = null, CancellationToken cancellationToken = default) + public Task> GetActivatedContentTypes(string spaceId = null, CancellationToken cancellationToken = default) { - return await GetActivatedContentTypes(null, spaceId, cancellationToken); + return GetActivatedContentTypes(null, spaceId, cancellationToken); } /// @@ -341,11 +309,9 @@ public async Task> GetActivatedContentTypes(string spac /// An of . public async Task> GetActivatedContentTypes(string queryString, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}public/content_types/{queryString}", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}public/content_types/{queryString}", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var json = await GetJObjectFromResponse(res).ConfigureAwait(false); return json.SelectTokens("$..items[*]").Select(t => t.ToObject(Serializer)); } @@ -366,14 +332,9 @@ public async Task GetEditorInterface(string contentTypeId, stri throw new ArgumentException(nameof(contentTypeId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/editor_interface", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var editorInterface = jsonObject.ToObject(Serializer); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/editor_interface", cancellationToken).ConfigureAwait(false); - return editorInterface; + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -396,15 +357,10 @@ public async Task UpdateEditorInterface(EditorInterface editorI // not allowed to pass sys properties on the update call for some reason editorInterface.SystemProperties = null; - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/editor_interface", + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/editor_interface", ConvertObjectToJsonStringContent(editorInterface), cancellationToken, version).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var updatedEditorInterface = jsonObject.ToObject(Serializer); - - return updatedEditorInterface; + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -460,9 +416,9 @@ JObject ReconstructJsonObject(JObject oldObject) /// The id of the space. Will default to the one set when creating the client. /// A of items. /// There was an error when communicating with the Contentful API. - public async Task> GetEntriesCollection(QueryBuilder queryBuilder, string spaceId = null, CancellationToken cancellationToken = default) + public Task> GetEntriesCollection(QueryBuilder queryBuilder, string spaceId = null, CancellationToken cancellationToken = default) { - return await GetEntriesCollection(queryBuilder?.Build(), spaceId, cancellationToken).ConfigureAwait(false); + return GetEntriesCollection(queryBuilder?.Build(), spaceId, cancellationToken); } /// @@ -477,13 +433,11 @@ public async Task> GetEntriesCollection(QueryBuilder< /// There was an error when communicating with the Contentful API. public async Task> GetEntriesCollection(string queryString = null, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries{queryString}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries{queryString}", cancellationToken).ConfigureAwait(false); var isContentfulResource = typeof(IContentfulResource).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); ReplaceMetaData(jsonObject); @@ -530,15 +484,10 @@ public async Task> CreateEntry(Entry entry, string conte throw new ArgumentException("The content type id must be set.", nameof(contentTypeId)); } - var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries", + using var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries", ConvertObjectToJsonStringContent(new { fields = entry.Fields, metadata = entry.Metadata }), cancellationToken, null, contentTypeId).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var updatedEntry = jsonObject.ToObject>(Serializer); - - return updatedEntry; + return await GetObjectFromResponse>(res).ConfigureAwait(false); } /// @@ -576,15 +525,10 @@ public async Task> CreateOrUpdateEntry(Entry entry, stri throw new ArgumentException("The id of the entry must be set."); } - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entry.SystemProperties.Id}", + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entry.SystemProperties.Id}", ConvertObjectToJsonStringContent(new { fields = entry.Fields, metadata = entry.Metadata }), cancellationToken, version, contentTypeId).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var updatedEntry = jsonObject.ToObject>(Serializer); - - return updatedEntry; + return await GetObjectFromResponse>(res).ConfigureAwait(false); } /// @@ -661,8 +605,8 @@ public async Task> CreateEntryForLocale(object entry, string id, /// The updated . public async Task> UpdateEntryForLocale(object entry, string id, string locale = null, string spaceId = null, CancellationToken cancellationToken = default) { - var entryToUpdate = await GetEntry(id, spaceId); - var contentType = await GetContentType(entryToUpdate.SystemProperties.ContentType.SystemProperties.Id, spaceId); + var entryToUpdate = await GetEntry(id, spaceId, cancellationToken); + var contentType = await GetContentType(entryToUpdate.SystemProperties.ContentType.SystemProperties.Id, spaceId, cancellationToken); var allFieldIds = contentType.Fields.Select(f => f.Id); if (string.IsNullOrEmpty(locale)) @@ -707,11 +651,9 @@ public async Task> GetEntry(string entryId, string spaceId = null throw new ArgumentException(nameof(entryId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}", cancellationToken).ConfigureAwait(false); - var jObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jObject = await GetJObjectFromResponse(res).ConfigureAwait(false); if (jObject.TryGetValue("metadata", out var val)) { @@ -737,7 +679,7 @@ public async Task DeleteEntry(string entryId, int version, string spaceId = null throw new ArgumentException(nameof(entryId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}", cancellationToken, version).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}", cancellationToken, version).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -759,11 +701,9 @@ public async Task> PublishEntry(string entryId, int version, stri throw new ArgumentException(nameof(entryId)); } - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/published", null, cancellationToken, version).ConfigureAwait(false); + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/published", null, cancellationToken, version).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - return JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)).ToObject>(Serializer); + return await GetObjectFromResponse>(res).ConfigureAwait(false); } /// @@ -783,11 +723,9 @@ public async Task> UnpublishEntry(string entryId, int version, st throw new ArgumentException(nameof(entryId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/published", cancellationToken, version).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/published", cancellationToken, version).ConfigureAwait(false); - return JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)).ToObject>(Serializer); + return await GetObjectFromResponse>(res).ConfigureAwait(false); } /// @@ -807,11 +745,9 @@ public async Task> ArchiveEntry(string entryId, int version, stri throw new ArgumentException(nameof(entryId)); } - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/archived", null, cancellationToken, version).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/archived", null, cancellationToken, version).ConfigureAwait(false); - return JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)).ToObject>(Serializer); + return await GetObjectFromResponse>(res).ConfigureAwait(false); } /// @@ -831,11 +767,9 @@ public async Task> UnarchiveEntry(string entryId, int version, st throw new ArgumentException(nameof(entryId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/archived", cancellationToken, version).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/archived", cancellationToken, version).ConfigureAwait(false); - return JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)).ToObject>(Serializer); + return await GetObjectFromResponse>(res).ConfigureAwait(false); } /// @@ -846,9 +780,9 @@ public async Task> UnarchiveEntry(string entryId, int version, st /// The optional cancellation token to cancel the operation. /// A of . /// There was an error when communicating with the Contentful API. - public async Task> GetAssetsCollection(QueryBuilder queryBuilder, string spaceId = null, CancellationToken cancellationToken = default) + public Task> GetAssetsCollection(QueryBuilder queryBuilder, string spaceId = null, CancellationToken cancellationToken = default) { - return await GetAssetsCollection(queryBuilder?.Build(), spaceId, cancellationToken).ConfigureAwait(false); + return GetAssetsCollection(queryBuilder?.Build(), spaceId, cancellationToken); } /// @@ -861,11 +795,9 @@ public async Task> GetAssetsCollection(Que /// There was an error when communicating with the Contentful API. public async Task> GetAssetsCollection(string queryString = null, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{queryString}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{queryString}", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var assets = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = assets; @@ -882,11 +814,9 @@ public async Task> GetAssetsCollection(str /// There was an error when communicating with the Contentful API. public async Task> GetPublishedAssetsCollection(string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}public/assets", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}public/assets", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var assets = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = assets; @@ -910,13 +840,9 @@ public async Task GetAsset(string assetId, string spaceId = nul throw new ArgumentException(nameof(assetId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{assetId}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{assetId}", cancellationToken).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -935,7 +861,7 @@ public async Task DeleteAsset(string assetId, int version, string spaceId = null throw new ArgumentException(nameof(assetId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{assetId}", cancellationToken, version).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{assetId}", cancellationToken, version).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -957,13 +883,9 @@ public async Task PublishAsset(string assetId, int version, str throw new ArgumentException(nameof(assetId)); } - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{assetId}/published", null, cancellationToken, version).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{assetId}/published", null, cancellationToken, version).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -983,13 +905,9 @@ public async Task UnpublishAsset(string assetId, int version, s throw new ArgumentException(nameof(assetId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{assetId}/published", cancellationToken, version).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{assetId}/published", cancellationToken, version).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1013,11 +931,7 @@ public async Task ArchiveAsset(string assetId, int version, str res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{assetId}/archived", null, cancellationToken, version).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1037,13 +951,9 @@ public async Task UnarchiveAsset(string assetId, int version, s throw new ArgumentException(nameof(assetId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{assetId}/archived", cancellationToken, version).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{assetId}/archived", cancellationToken, version).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1126,7 +1036,7 @@ public async Task CreateOrUpdateAsset(ManagementAsset asset, st throw new ArgumentException("The id of the asset must be set."); } - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{asset.SystemProperties.Id}", + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets/{asset.SystemProperties.Id}", ConvertObjectToJsonStringContent(new { fields = new { title = asset.Title, description = asset.Description, file = asset.Files }, @@ -1134,12 +1044,7 @@ public async Task CreateOrUpdateAsset(ManagementAsset asset, st } ), cancellationToken, version).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var updatedAsset = jsonObject.ToObject(Serializer); - - return updatedAsset; + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1152,15 +1057,10 @@ public async Task CreateOrUpdateAsset(ManagementAsset asset, st /// There was an error when communicating with the Contentful API. public async Task CreateAsset(ManagementAsset asset, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets", + using var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}assets", ConvertObjectToJsonStringContent(new { fields = new { title = asset.Title, description = asset.Description, file = asset.Files } }), cancellationToken, null).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var createdAsset = jsonObject.ToObject(Serializer); - - return createdAsset; + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1172,11 +1072,9 @@ public async Task CreateAsset(ManagementAsset asset, string spa /// There was an error when communicating with the Contentful API. public async Task> GetLocalesCollection(string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}locales", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}locales", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false);; var collection = jsonObject.ToObject>(Serializer); var locales = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = locales; @@ -1194,7 +1092,7 @@ public async Task> GetLocalesCollection(string spac /// There was an error when communicating with the Contentful API. public async Task CreateLocale(Locale locale, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}locales", + using var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}locales", ConvertObjectToJsonStringContent( new { @@ -1206,11 +1104,7 @@ public async Task CreateLocale(Locale locale, string spaceId = null, Can optional = locale.Optional }), cancellationToken, null).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1229,13 +1123,9 @@ public async Task GetLocale(string localeId, string spaceId = null, Canc throw new ArgumentException("The localeId must be set."); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}locales/{localeId}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}locales/{localeId}", cancellationToken).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1253,7 +1143,7 @@ public async Task UpdateLocale(Locale locale, string spaceId = null, Can throw new ArgumentException("The id of the Locale must be set."); } - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}locales/{locale.SystemProperties.Id}", ConvertObjectToJsonStringContent(new + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}locales/{locale.SystemProperties.Id}", ConvertObjectToJsonStringContent(new { code = locale.Code, contentDeliveryApi = locale.ContentDeliveryApi, @@ -1263,11 +1153,7 @@ public async Task UpdateLocale(Locale locale, string spaceId = null, Can optional = locale.Optional }), cancellationToken, locale.SystemProperties.Version).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1285,7 +1171,7 @@ public async Task DeleteLocale(string localeId, string spaceId = null, Cancellat throw new ArgumentException("The localeId must be set."); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}locales/{localeId}", cancellationToken).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}locales/{localeId}", cancellationToken).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -1300,11 +1186,9 @@ public async Task DeleteLocale(string localeId, string spaceId = null, Cancellat /// There was an error when communicating with the Contentful API. public async Task> GetWebhooksCollection(string spaceId = null, string queryString = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhook_definitions{queryString}", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhook_definitions{queryString}", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var hooks = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = hooks; @@ -1325,13 +1209,9 @@ public async Task CreateWebhook(Webhook webhook, string spaceId = null, //Not allowed to post system properties webhook.SystemProperties = null; - var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhook_definitions", ConvertObjectToJsonStringContent(webhook), cancellationToken, null).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhook_definitions", ConvertObjectToJsonStringContent(webhook), cancellationToken, null).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1356,13 +1236,9 @@ public async Task CreateOrUpdateWebhook(Webhook webhook, string spaceId //Not allowed to post system properties webhook.SystemProperties = null; - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhook_definitions/{id}", ConvertObjectToJsonStringContent(webhook), cancellationToken, version).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhook_definitions/{id}", ConvertObjectToJsonStringContent(webhook), cancellationToken, version).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1381,13 +1257,9 @@ public async Task GetWebhook(string webhookId, string spaceId = null, C throw new ArgumentException("The id of the webhook must be set.", nameof(webhookId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhook_definitions/{webhookId}", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhook_definitions/{webhookId}", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1405,7 +1277,7 @@ public async Task DeleteWebhook(string webhookId, string spaceId = null, Cancell throw new ArgumentException("The id of the webhook must be set", nameof(webhookId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhook_definitions/{webhookId}", cancellationToken).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhook_definitions/{webhookId}", cancellationToken).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -1426,11 +1298,9 @@ public async Task> GetWebhookCallDetail throw new ArgumentException("The id of the webhook must be set.", nameof(webhookId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhooks/{webhookId}/calls", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhooks/{webhookId}/calls", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var hooks = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = hooks; @@ -1460,13 +1330,9 @@ public async Task GetWebhookCallDetails(string callId, strin throw new ArgumentException("The id of the webhook must be set.", nameof(webhookId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhooks/{webhookId}/calls/{callId}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhooks/{webhookId}/calls/{callId}", cancellationToken).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1485,11 +1351,9 @@ public async Task GetWebhookHealth(string webhookId, stri throw new ArgumentException("The id of the webhook must be set.", nameof(webhookId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhooks/{webhookId}/health", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/webhooks/{webhookId}/health", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var health = new WebhookHealthResponse() { SystemProperties = jsonObject["sys"]?.ToObject(Serializer), @@ -1515,13 +1379,9 @@ public async Task GetRole(string roleId, string spaceId = null, Cancellati throw new ArgumentException("The id of the role must be set", nameof(roleId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/roles/{roleId}", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/roles/{roleId}", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1533,11 +1393,9 @@ public async Task GetRole(string roleId, string spaceId = null, Cancellati /// There was an error when communicating with the Contentful API. public async Task> GetAllRoles(string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/roles", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/roles", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var roles = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = roles; @@ -1558,13 +1416,9 @@ public async Task CreateRole(Role role, string spaceId = null, Cancellatio //Not allowed to post system properties role.SystemProperties = null; - var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/roles", ConvertObjectToJsonStringContent(role), cancellationToken, null).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/roles", ConvertObjectToJsonStringContent(role), cancellationToken, null).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1588,13 +1442,9 @@ public async Task UpdateRole(Role role, string spaceId = null, Cancellatio //Not allowed to post system properties role.SystemProperties = null; - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/roles/{id}", ConvertObjectToJsonStringContent(role), cancellationToken, null).ConfigureAwait(false); + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/roles/{id}", ConvertObjectToJsonStringContent(role), cancellationToken, null).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1612,7 +1462,7 @@ public async Task DeleteRole(string roleId, string spaceId = null, CancellationT throw new ArgumentException("The id of the role must be set", nameof(roleId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/roles/{roleId}", cancellationToken).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/roles/{roleId}", cancellationToken).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -1631,11 +1481,9 @@ public async Task> GetAllSnapshotsForEntry(string throw new ArgumentException("The id of the entry must be set", nameof(entryId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/snapshots", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/snapshots", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var snapshots = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = snapshots; @@ -1663,13 +1511,9 @@ public async Task GetSnapshotForEntry(string snapshotId, string entryI throw new ArgumentException("The id of the entry must be set.", nameof(entryId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/snapshots/{snapshotId}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}entries/{entryId}/snapshots/{snapshotId}", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1686,11 +1530,9 @@ public async Task> GetAllSnapshotsForC throw new ArgumentException("The id of the content type must be set.", nameof(contentTypeId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/snapshots", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/snapshots", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var snapshots = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = snapshots; @@ -1718,13 +1560,9 @@ public async Task GetSnapshotForContentType(string snapshot throw new ArgumentException("The id of the content type must be set.", nameof(contentTypeId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/snapshots/{snapshotId}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}content_types/{contentTypeId}/snapshots/{snapshotId}", cancellationToken).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } @@ -1736,11 +1574,9 @@ public async Task GetSnapshotForContentType(string snapshot /// A collection of . public async Task> GetSpaceMemberships(string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/space_memberships", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/space_memberships", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var memberships = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = memberships; @@ -1758,13 +1594,9 @@ public async Task> GetSpaceMemberships(str /// There was an error when communicating with the Contentful API. public async Task CreateSpaceMembership(SpaceMembership spaceMembership, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/space_memberships", ConvertObjectToJsonStringContent(spaceMembership), cancellationToken, null).ConfigureAwait(false); + using var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/space_memberships", ConvertObjectToJsonStringContent(spaceMembership), cancellationToken, null).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1783,13 +1615,9 @@ public async Task GetSpaceMembership(string spaceMembershipId, throw new ArgumentException("The id of the space membership must be set", nameof(spaceMembershipId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/space_memberships/{spaceMembershipId}", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/space_memberships/{spaceMembershipId}", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1808,14 +1636,10 @@ public async Task UpdateSpaceMembership(SpaceMembership spaceMe throw new ArgumentException("The id of the space membership id must be set", nameof(spaceMembership)); } - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/space_memberships/{spaceMembership.SystemProperties.Id}", + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/space_memberships/{spaceMembership.SystemProperties.Id}", ConvertObjectToJsonStringContent(spaceMembership), cancellationToken, null).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1833,7 +1657,7 @@ public async Task DeleteSpaceMembership(string spaceMembershipId, string spaceId throw new ArgumentException("The id of the space membership must be set", nameof(spaceMembershipId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/space_memberships/{spaceMembershipId}", cancellationToken).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/space_memberships/{spaceMembershipId}", cancellationToken).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -1847,11 +1671,9 @@ public async Task DeleteSpaceMembership(string spaceMembershipId, string spaceId /// There was an error when communicating with the Contentful API. public async Task> GetAllApiKeys(string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/api_keys", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/api_keys", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var keys = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = keys; @@ -1868,11 +1690,9 @@ public async Task> GetAllApiKeys(string spaceId = n /// There was an error when communicating with the Contentful API. public async Task> GetAllPreviewApiKeys(string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/preview_api_keys", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/preview_api_keys", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var keys = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = keys; @@ -1890,13 +1710,9 @@ public async Task> GetAllPreviewApiKeys(string spac /// There was an error when communicating with the Contentful API. public async Task GetApiKey(string apiKeyId, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/api_keys/{apiKeyId}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/api_keys/{apiKeyId}", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1909,13 +1725,9 @@ public async Task GetApiKey(string apiKeyId, string spaceId = null, Canc /// There was an error when communicating with the Contentful API. public async Task GetPreviewApiKey(string apiKeyId, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/preview_api_keys/{apiKeyId}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/preview_api_keys/{apiKeyId}", cancellationToken).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1934,13 +1746,9 @@ public async Task CreateApiKey(string name, string description, string s throw new ArgumentException("The name of the api key must be set.", nameof(name)); } - var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/api_keys", ConvertObjectToJsonStringContent(new { name, description }), cancellationToken, null).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/api_keys", ConvertObjectToJsonStringContent(new { name, description }), cancellationToken, null).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1966,14 +1774,10 @@ public async Task UpdateApiKey(string id, string name, string descriptio throw new ArgumentException("The id of the api key must be set.", nameof(id)); } - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/api_keys/{id}", ConvertObjectToJsonStringContent(new { name, description }), + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/api_keys/{id}", ConvertObjectToJsonStringContent(new { name, description }), cancellationToken, version).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -1985,7 +1789,7 @@ public async Task UpdateApiKey(string id, string name, string descriptio /// A with metadata of the upload. public async Task DeleteApiKey(string apiKeyId, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/api_keys/{apiKeyId}", cancellationToken).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/api_keys/{apiKeyId}", cancellationToken).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -1999,11 +1803,9 @@ public async Task DeleteApiKey(string apiKeyId, string spaceId = null, Cancellat /// There was an error when communicating with the Contentful API. public async Task> GetAllUsers(string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/users", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/users", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var keys = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = keys; @@ -2027,13 +1829,9 @@ public async Task GetUser(string userId, string spaceId = null, Cancellati throw new ArgumentException("The id of the user must be set", nameof(userId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/users/{userId}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/users/{userId}", cancellationToken).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2044,13 +1842,9 @@ public async Task GetUser(string userId, string spaceId = null, Cancellati /// There was an error when communicating with the Contentful API. public async Task GetCurrentUser(CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_directApiUrl}users/me", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_directApiUrl}users/me", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2062,13 +1856,9 @@ public async Task GetCurrentUser(CancellationToken cancellationToken = def /// A with metadata of the upload. public async Task GetUpload(string uploadId, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUploadUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}uploads/{uploadId}", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUploadUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}uploads/{uploadId}", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2083,13 +1873,9 @@ public async Task UploadFile(byte[] bytes, string spaceId = nul var byteArrayContent = new ByteArrayContent(bytes); byteArrayContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); - var res = await PostAsync($"{_baseUploadUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}uploads", byteArrayContent, cancellationToken, null).ConfigureAwait(false); + using var res = await PostAsync($"{_baseUploadUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}uploads", byteArrayContent, cancellationToken, null).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2101,7 +1887,7 @@ public async Task UploadFile(byte[] bytes, string spaceId = nul /// A with metadata of the upload. public async Task DeleteUpload(string uploadId, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await DeleteAsync($"{_baseUploadUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}uploads/{uploadId}", cancellationToken).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUploadUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}uploads/{uploadId}", cancellationToken).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -2147,11 +1933,9 @@ public async Task UploadFileAndCreateAsset(ManagementAsset asse /// There was an error when communicating with the Contentful API. public async Task> GetAllExtensions(string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}extensions", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}extensions", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var keys = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = keys; @@ -2172,14 +1956,10 @@ public async Task CreateExtension(UiExtension extension, string spa // The api does not accept a sys object in the extension creation. extension.SystemProperties = null; - var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}extensions", + using var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}extensions", ConvertObjectToJsonStringContent(extension), cancellationToken, null).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2203,15 +1983,11 @@ public async Task CreateOrUpdateExtension(UiExtension extension, st // The api does not accept a sys object in the extension creation. extension.SystemProperties = null; - var res = await PutAsync( + using var res = await PutAsync( $"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}extensions/{id}", ConvertObjectToJsonStringContent(extension), cancellationToken, version).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return json.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2230,13 +2006,9 @@ public async Task GetExtension(string extensionId, string spaceId = throw new ArgumentException("The id of the extension must be set", nameof(extensionId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}extensions/{extensionId}", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}extensions/{extensionId}", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2254,7 +2026,7 @@ public async Task DeleteExtension(string extensionId, string spaceId = null, Can throw new ArgumentException(nameof(extensionId)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}extensions/{extensionId}", cancellationToken).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}extensions/{extensionId}", cancellationToken).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -2268,18 +2040,14 @@ public async Task DeleteExtension(string extensionId, string spaceId = null, Can /// There was an error when communicating with the Contentful API. public async Task CreateManagementToken(ManagementToken token, CancellationToken cancellationToken = default) { - var res = await PostAsync($"{_directApiUrl}users/me/access_tokens", + using var res = await PostAsync($"{_directApiUrl}users/me/access_tokens", ConvertObjectToJsonStringContent(new { name = token.Name, scopes = token.Scopes }), cancellationToken, null).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2291,11 +2059,9 @@ public async Task CreateManagementToken(ManagementToken token, /// There was an error when communicating with the Contentful API. public async Task> GetAllManagementTokens(CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_directApiUrl}users/me/access_tokens", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_directApiUrl}users/me/access_tokens", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var keys = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = keys; @@ -2318,13 +2084,9 @@ public async Task GetManagementToken(string managementTokenId, throw new ArgumentException("The id of the token must be set", nameof(managementTokenId)); } - var res = await GetAsync($"{_directApiUrl}users/me/access_tokens/{managementTokenId}", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_directApiUrl}users/me/access_tokens/{managementTokenId}", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2342,13 +2104,9 @@ public async Task RevokeManagementToken(string managementTokenI throw new ArgumentException("The id of the token must be set", nameof(managementTokenId)); } - var res = await PutAsync($"{_directApiUrl}users/me/access_tokens/{managementTokenId}/revoked", null, cancellationToken, null).ConfigureAwait(false); + using var res = await PutAsync($"{_directApiUrl}users/me/access_tokens/{managementTokenId}/revoked", null, cancellationToken, null).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2359,11 +2117,9 @@ public async Task RevokeManagementToken(string managementTokenI /// There was an error when communicating with the Contentful API. public async Task> GetOrganizations(CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_directApiUrl}organizations", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_directApiUrl}organizations", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var orgs = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = orgs; @@ -2380,11 +2136,9 @@ public async Task> GetOrganizations(Cancellat /// There was an error when communicating with the Contentful API. public async Task> GetEnvironments(string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments", cancellationToken).ConfigureAwait(false); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments", cancellationToken).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var environments = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = environments; @@ -2408,13 +2162,9 @@ public async Task CreateEnvironment(string name, string s throw new ArgumentException("You must provide a name for the environment.", nameof(name)); } - var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments", ConvertObjectToJsonStringContent(new { name }), cancellationToken, null).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await PostAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments", ConvertObjectToJsonStringContent(new { name }), cancellationToken, null).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2440,13 +2190,9 @@ public async Task CreateOrUpdateEnvironment(string id, st throw new ArgumentException("You must provide a name for the environment.", nameof(name)); } - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments/{id}", ConvertObjectToJsonStringContent(new { name }), cancellationToken, version: version).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments/{id}", ConvertObjectToJsonStringContent(new { name }), cancellationToken, version: version).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2476,15 +2222,15 @@ public async Task CloneEnvironment(string id, string name { throw new ArgumentException("You must provide an id for the source environment.", nameof(sourceEnvironmentId)); } - var sourceHeader = new KeyValuePair>("x-contentful-source-environment", new[] { sourceEnvironmentId }); - - var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments/{id}", ConvertObjectToJsonStringContent(new { name }), cancellationToken, null, additionalHeaders: new[] { sourceHeader }.ToList()).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); + var sourceHeaders = new List>>(1) + { + new("x-contentful-source-environment", [sourceEnvironmentId]) + }; - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await PutAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments/{id}", ConvertObjectToJsonStringContent(new { name }), cancellationToken, null, additionalHeaders: sourceHeaders).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2503,13 +2249,9 @@ public async Task GetEnvironment(string id, string spaceI throw new ArgumentException("You must provide an id for the environment.", nameof(id)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments/{id}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments/{id}", cancellationToken).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2527,7 +2269,7 @@ public async Task DeleteEnvironment(string id, string spaceId = null, Cancellati throw new ArgumentException("You must provide an id for the environment.", nameof(id)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments/{id}", cancellationToken).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/environments/{id}", cancellationToken).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -2542,11 +2284,9 @@ public async Task DeleteEnvironment(string id, string spaceId = null, Cancellati public async Task> GetUsagePeriods(string organizationId, CancellationToken cancellationToken = default) { var alphaHeader = new KeyValuePair>("x-contentful-enable-alpha-feature", new[] { "usage-insights" }); - var res = await GetAsync($"{_directApiUrl}organizations/{organizationId}/usage_periods", cancellationToken, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); + using var res = await GetAsync($"{_directApiUrl}organizations/{organizationId}/usage_periods", cancellationToken, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var periods = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); @@ -2564,11 +2304,9 @@ public async Task> GetUsagePeriods(string orga public async Task> GetOrganizationMemberships(string organizationId, string queryString = null, CancellationToken cancellationToken = default) { var alphaHeader = new KeyValuePair>("x-contentful-enable-alpha-feature", new[] { "organization-user-management-api" }); - var res = await GetAsync($"{_directApiUrl}organizations/{organizationId}/organization_memberships{queryString}", cancellationToken, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); + using var res = await GetAsync($"{_directApiUrl}organizations/{organizationId}/organization_memberships{queryString}", cancellationToken, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var memberships = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); @@ -2590,10 +2328,9 @@ public async Task> GetResourceUsage(string organi { var alphaHeader = new KeyValuePair>("x-contentful-enable-alpha-feature", new[] { "usage-insights" }); - var res = await GetAsync($"{_directApiUrl}organizations/{organizationId}/usages/{type}{queryString}", cancellationToken, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync($"{_directApiUrl}organizations/{organizationId}/usages/{type}{queryString}", cancellationToken, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var apiUsage = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = apiUsage; @@ -2615,10 +2352,9 @@ public async Task CreateOrganizationMembership(string or { var alphaHeader = new KeyValuePair>("x-contentful-enable-alpha-feature", new[] { "organization-user-management-api" }); - var res = await PostAsync($"{_directApiUrl}organizations/{organizationId}/organization_memberships", ConvertObjectToJsonStringContent(new { role, email, suppressInvitation }), cancellationToken, null, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await PostAsync($"{_directApiUrl}organizations/{organizationId}/organization_memberships", ConvertObjectToJsonStringContent(new { role, email, suppressInvitation }), cancellationToken, null, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var apiUsage = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = apiUsage; @@ -2642,13 +2378,9 @@ public async Task GetOrganizationMembership(string membe } var alphaHeader = new KeyValuePair>("x-contentful-enable-alpha-feature", new[] { "organization-user-management-api" }); - var res = await GetAsync($"{_directApiUrl}organizations/{organizationId}/organization_memberships/{membershipId}", cancellationToken, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await GetAsync($"{_directApiUrl}organizations/{organizationId}/organization_memberships/{membershipId}", cancellationToken, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2668,14 +2400,10 @@ public async Task UpdateOrganizationMembership(string ro } var alphaHeader = new KeyValuePair>("x-contentful-enable-alpha-feature", new[] { "organization-user-management-api" }); - var res = await PutAsync($"{_directApiUrl}organizations/{organizationId}/organization_memberships/{membershipId}", + using var res = await PutAsync($"{_directApiUrl}organizations/{organizationId}/organization_memberships/{membershipId}", ConvertObjectToJsonStringContent(new { role }), cancellationToken, null, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2694,7 +2422,7 @@ public async Task DeleteOrganizationMembership(string membershipId, string organ } var alphaHeader = new KeyValuePair>("x-contentful-enable-alpha-feature", new[] { "organization-user-management-api" }); - var res = await DeleteAsync($"{_directApiUrl}organizations/{organizationId}/organization_memberships/{membershipId}", cancellationToken, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); + using var res = await DeleteAsync($"{_directApiUrl}organizations/{organizationId}/organization_memberships/{membershipId}", cancellationToken, additionalHeaders: new[] { alphaHeader }.ToList()).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -2709,11 +2437,9 @@ public async Task DeleteOrganizationMembership(string membershipId, string organ /// There was an error when communicating with the Contentful API. public async Task> GetContentTagsCollection(string queryString = null, string spaceId = null, CancellationToken cancellationToken = default) { - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}tags{queryString}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}tags{queryString}", cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); var collection = jsonObject.ToObject>(Serializer); var tags = jsonObject.SelectTokens("$..items[*]").Select(c => c.ToObject(Serializer)); collection.Items = tags; @@ -2737,13 +2463,9 @@ public async Task GetContentTag(string contentTagId, string spaceId throw new ArgumentException(nameof(contentTagId)); } - var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}tags/{contentTagId}", cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + using var res = await GetAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}tags/{contentTagId}", cancellationToken).ConfigureAwait(false); - return jsonObject.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2769,15 +2491,11 @@ public async Task CreateContentTag(string name, string id, bool publ throw new ArgumentException("The id of the content tag must be set.", nameof(id)); } - var res = await PutAsync( + using var res = await PutAsync( $"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}tags/{id}", ConvertObjectToJsonStringContent(new { name, sys = new { id, type = "tag", visibility = publiclyVisible ? "public" : "private" } }), cancellationToken, null).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return json.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2803,15 +2521,11 @@ public async Task UpdateContentTag(string name, string id, int versi throw new ArgumentException("The id of the content tag must be set.", nameof(id)); } - var res = await PutAsync( + using var res = await PutAsync( $"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}tags/{id}", ConvertObjectToJsonStringContent(new { name, sys = new { id, type = "tag" } }), cancellationToken, version).ConfigureAwait(false); - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var json = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - - return json.ToObject(Serializer); + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2830,7 +2544,7 @@ public async Task DeleteContentTag(string id, int? version, string spaceId = nul throw new ArgumentException(nameof(id)); } - var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}tags/{id}", cancellationToken, version).ConfigureAwait(false); + using var res = await DeleteAsync($"{_baseUrl}{spaceId ?? _options.SpaceId}/{EnvironmentsBase}tags/{id}", cancellationToken, version).ConfigureAwait(false); await EnsureSuccessfulResult(res).ConfigureAwait(false); } @@ -2844,9 +2558,9 @@ public async Task DeleteContentTag(string id, int? version, string spaceId = nul /// The id of the space. Will default to the one set when creating the client. /// A of items. /// There was an error when communicating with the Contentful API. - public async Task> GetScheduledActions(ScheduledActionQueryBuilder queryBuilder, string spaceId = null, CancellationToken cancellationToken = default) + public Task> GetScheduledActions(ScheduledActionQueryBuilder queryBuilder, string spaceId = null, CancellationToken cancellationToken = default) { - return await GetScheduledActions(queryBuilder?.Build(), spaceId, cancellationToken).ConfigureAwait(false); + return GetScheduledActions(queryBuilder?.Build(), spaceId, cancellationToken); } public async Task> GetScheduledActions(string queryString = null, string spaceId = null, CancellationToken cancellationToken = default) @@ -2872,11 +2586,9 @@ public async Task> GetScheduledActions(string querySt /// There was an error when communicating with the Contentful API. public async Task> GetScheduledActions(string nextOrPreviousPageLink, CancellationToken cancellationToken = default) { - var res = await GetAsync(nextOrPreviousPageLink, cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); + using var res = await GetAsync(nextOrPreviousPageLink, cancellationToken).ConfigureAwait(false); - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); + var jsonObject = await GetJObjectFromResponse(res).ConfigureAwait(false); ReplaceMetaData(jsonObject); @@ -2894,9 +2606,9 @@ public async Task> GetScheduledActions(string nextOrP /// /// Id of the scheduled action /// - public async Task GetScheduledAction(string scheduledActionId, CancellationToken cancellationToken = default) + public Task GetScheduledAction(string scheduledActionId, CancellationToken cancellationToken = default) { - return await GetScheduledAction(scheduledActionId, _options.Environment, _options.SpaceId, cancellationToken).ConfigureAwait(false); ; + return GetScheduledAction(scheduledActionId, _options.Environment, _options.SpaceId, cancellationToken); } /// @@ -2906,9 +2618,9 @@ public async Task GetScheduledAction(string scheduledActionId, Cancellatio /// Id of the scheduled action /// Specify environment /// - public async Task GetScheduledAction(string scheduledActionId, string environmentId, CancellationToken cancellationToken = default) + public Task GetScheduledAction(string scheduledActionId, string environmentId, CancellationToken cancellationToken = default) { - return await GetScheduledAction(scheduledActionId, environmentId, _options.SpaceId, cancellationToken).ConfigureAwait(false); ; + return GetScheduledAction(scheduledActionId, environmentId, _options.SpaceId, cancellationToken); } /// @@ -2923,14 +2635,9 @@ public async Task GetScheduledAction(string scheduledActionId, string envi { var requestUrl = $"{_baseUrl}{spaceId ?? _options.SpaceId}/scheduled_actions/{scheduledActionId}?environment.sys.id={environmentId ?? _options.Environment}"; - var res = await GetAsync(requestUrl, cancellationToken).ConfigureAwait(false); - - await EnsureSuccessfulResult(res).ConfigureAwait(false); - - var jsonObject = JObject.Parse(await res.Content.ReadAsStringAsync().ConfigureAwait(false)); - var scheduledAction = jsonObject.ToObject(Serializer); + using var res = await GetAsync(requestUrl, cancellationToken).ConfigureAwait(false); - return scheduledAction; + return await GetObjectFromResponse(res).ConfigureAwait(false); } /// @@ -2947,10 +2654,7 @@ public async Task CreateScheduledAction(ScheduledAction schedul var result = await PostAsync(requestUrl, ConvertObjectToJsonStringContent(GetScheduledActionRequestObject(scheduledAction)), cancellationToken, 0); - await EnsureSuccessfulResult(result).ConfigureAwait(false); - - var json = JObject.Parse(await result.Content.ReadAsStringAsync().ConfigureAwait(false)); - return json.ToObject(Serializer); + return await GetObjectFromResponse(result).ConfigureAwait(false); } /// @@ -2970,10 +2674,7 @@ public async Task UpdateScheduledAction(ScheduledAction schedul var result = await PutAsync(requestUrl, ConvertObjectToJsonStringContent(GetScheduledActionRequestObject(scheduledAction)), cancellationToken, scheduledAction.SystemProperties.Version); - await EnsureSuccessfulResult(result).ConfigureAwait(false); - - var json = JObject.Parse(await result.Content.ReadAsStringAsync().ConfigureAwait(false)); - return json.ToObject(Serializer); + return await GetObjectFromResponse(result).ConfigureAwait(false); } private object GetScheduledActionRequestObject(ScheduledAction scheduledAction) @@ -3004,33 +2705,30 @@ public async Task CancelScheduledAction(string scheduledActionI var result = await DeleteAsync(requestUrl, cancellationToken); - await EnsureSuccessfulResult(result).ConfigureAwait(false); - - var json = JObject.Parse(await result.Content.ReadAsStringAsync().ConfigureAwait(false)); - return json.ToObject(Serializer); + return await GetObjectFromResponse(result).ConfigureAwait(false); } - private async Task PostAsync(string url, HttpContent content, CancellationToken cancellationToken, int? version, string contentTypeId = null, string organisationId = null, List>> additionalHeaders = null) + private Task PostAsync(string url, HttpContent content, CancellationToken cancellationToken, int? version, string contentTypeId = null, string organisationId = null, List>> additionalHeaders = null) { - return await SendHttpRequest(url, HttpMethod.Post, _options.ManagementApiKey, cancellationToken, content, version, contentTypeId, organisationId, additionalHeaders: additionalHeaders).ConfigureAwait(false); + return SendHttpRequest(url, HttpMethod.Post, _options.ManagementApiKey, cancellationToken, content, version, contentTypeId, organisationId, additionalHeaders: additionalHeaders); } - private async Task PutAsync(string url, HttpContent content, CancellationToken cancellationToken, int? version, string contentTypeId = null, string organisationId = null, List>> additionalHeaders = null) + private Task PutAsync(string url, HttpContent content, CancellationToken cancellationToken, int? version, string contentTypeId = null, string organisationId = null, List>> additionalHeaders = null) { - return await SendHttpRequest(url, HttpMethod.Put, _options.ManagementApiKey, cancellationToken, content, version, contentTypeId, organisationId, additionalHeaders: additionalHeaders).ConfigureAwait(false); + return SendHttpRequest(url, HttpMethod.Put, _options.ManagementApiKey, cancellationToken, content, version, contentTypeId, organisationId, additionalHeaders: additionalHeaders); } - private async Task DeleteAsync(string url, CancellationToken cancellationToken, int? version = null, List>> additionalHeaders = null) + private Task DeleteAsync(string url, CancellationToken cancellationToken, int? version = null, List>> additionalHeaders = null) { - return await SendHttpRequest(url, HttpMethod.Delete, _options.ManagementApiKey, cancellationToken, version: version, additionalHeaders: additionalHeaders).ConfigureAwait(false); + return SendHttpRequest(url, HttpMethod.Delete, _options.ManagementApiKey, cancellationToken, version: version, additionalHeaders: additionalHeaders); } - private async Task GetAsync(string url, CancellationToken cancellationToken, int? version = null, List>> additionalHeaders = null) + private Task GetAsync(string url, CancellationToken cancellationToken, int? version = null, List>> additionalHeaders = null) { - return await SendHttpRequest(url, HttpMethod.Get, _options.ManagementApiKey, cancellationToken, version: version, additionalHeaders: additionalHeaders).ConfigureAwait(false); + return SendHttpRequest(url, HttpMethod.Get, _options.ManagementApiKey, cancellationToken, version: version, additionalHeaders: additionalHeaders); } - private StringContent ConvertObjectToJsonStringContent(object ob) + private static StringContent ConvertObjectToJsonStringContent(object ob) { var serializedObject = ob.ConvertObjectToJsonString(); return new StringContent(serializedObject, Encoding.UTF8, "application/vnd.contentful.management.v1+json"); diff --git a/Contentful.Core/Extensions/JsonConversionExtensions.cs b/Contentful.Core/Extensions/JsonConversionExtensions.cs index 1b8ab45..e47b135 100644 --- a/Contentful.Core/Extensions/JsonConversionExtensions.cs +++ b/Contentful.Core/Extensions/JsonConversionExtensions.cs @@ -1,5 +1,11 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; using Contentful.Core.Configuration; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; namespace Contentful.Core.Extensions @@ -9,24 +15,58 @@ namespace Contentful.Core.Extensions /// public static class JsonConversionExtensions { - /// - /// Converts the object to Json to use when sending a parameter in the body of a request to the Contentful API. - /// - public static string ConvertObjectToJsonString(this object ob) + /// Deserializes an object of type T from the response + /// The response to deserialize from + /// The serializer to use + /// The type to deserialize into + /// The deserialized object + /// Thrown if the response is null + /// Thrown if response.Content is null + public static async Task GetObjectFromResponse(this HttpResponseMessage response, JsonSerializer serializer) { - var resolver = new CamelCasePropertyNamesContractResolver(); - resolver.NamingStrategy.OverrideSpecifiedNames = false; - - var settings = new JsonSerializerSettings - { - ContractResolver = resolver, - }; + if (response == null) throw new ArgumentNullException(nameof(response)); + if (response.Content == null) + throw new ArgumentException(nameof(response.Content) + " is null", nameof(response)); + using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + using var streamReader = new StreamReader(stream); + using var jsonReader = new JsonTextReader(streamReader); + return serializer.Deserialize(jsonReader); + } - settings.Converters.Add(new ExtensionJsonConverter()); + /// Deserializes a JObject from the response + /// The response to deserialize from + /// The deserialized JObject + /// Thrown if the response is null + /// Thrown if response.Content is null + public static async Task GetJObjectFromResponse(this HttpResponseMessage response) + { + if (response == null) throw new ArgumentNullException(nameof(response)); + if (response.Content == null) + throw new ArgumentException(nameof(response.Content) + " is null", nameof(response)); + using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + using var streamReader = new StreamReader(stream); + using var jsonReader = new JsonTextReader(streamReader); + return await JObject.LoadAsync(jsonReader).ConfigureAwait(false); + } - var serializedObject = JsonConvert.SerializeObject(ob, settings); + private static readonly JsonSerializerSettings SerializerSettings = new() + { + ContractResolver = new CamelCasePropertyNamesContractResolver + { + NamingStrategy = + { + OverrideSpecifiedNames = false + } + }, + Converters = new List + { + new ExtensionJsonConverter(), + }, + }; - return serializedObject; - } + /// + /// Converts the object to Json to use when sending a parameter in the body of a request to the Contentful API. + /// + public static string ConvertObjectToJsonString(this object ob) => JsonConvert.SerializeObject(ob, SerializerSettings); } } \ No newline at end of file diff --git a/Contentful.Core/Models/Management/IFieldValidation.cs b/Contentful.Core/Models/Management/IFieldValidation.cs index 0342071..83584e1 100644 --- a/Contentful.Core/Models/Management/IFieldValidation.cs +++ b/Contentful.Core/Models/Management/IFieldValidation.cs @@ -3,7 +3,6 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; namespace Contentful.Core.Models.Management @@ -466,7 +465,7 @@ public object CreateValidator() /// public class DateRangeValidator : IFieldValidator { - private string _min; + private readonly string _min; /// /// The minimum allowed date. @@ -482,7 +481,7 @@ public DateTime? Min } } - private string _max; + private readonly string _max; /// /// The maximum allowed date. @@ -573,7 +572,7 @@ public object CreateValidator() } - private int? GetCalculatedByteSize(int? value, string unit) + private static int? GetCalculatedByteSize(int? value, string unit) { if (value != null) { @@ -675,7 +674,7 @@ public object CreateValidator() } } - internal class Nodes + internal sealed class Nodes { public Nodes(NodesValidator validator) { diff --git a/Contentful.Core/Search/SelectVisitor.cs b/Contentful.Core/Search/SelectVisitor.cs index d49fa98..f19e6c2 100644 --- a/Contentful.Core/Search/SelectVisitor.cs +++ b/Contentful.Core/Search/SelectVisitor.cs @@ -1,14 +1,12 @@ using Contentful.Core.Models; using Newtonsoft.Json; using System; -using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -using System.Text; namespace Contentful.Core.Search { - internal class SelectVisitor : ExpressionVisitor + internal sealed class SelectVisitor : ExpressionVisitor { private readonly Type _sourceType; private readonly string _prefix;