diff --git a/TMDbLib/Client/TMDbClient.cs b/TMDbLib/Client/TMDbClient.cs index fc2e718..1410984 100644 --- a/TMDbLib/Client/TMDbClient.cs +++ b/TMDbLib/Client/TMDbClient.cs @@ -185,6 +185,7 @@ namespace TMDbLib.Client return await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); } + [System.Diagnostics.CodeAnalysis.SuppressMessage("IDisposableAnalyzers.Correctness", "IDISP003:Dispose previous before re-assigning.", Justification = "Only called from ctor")] private void Initialize(string baseUrl, bool useSsl, string apiKey) { if (string.IsNullOrWhiteSpace(baseUrl)) @@ -202,6 +203,7 @@ namespace TMDbLib.Client baseUrl = baseUrl.Substring("https://".Length); string httpScheme = useSsl ? "https" : "http"; + _client = new RestClient(new Uri(string.Format("{0}://{1}/{2}/", httpScheme, baseUrl, ApiVersion)), _serializer, WebProxy); _client.AddDefaultQueryString("api_key", apiKey); } @@ -272,7 +274,7 @@ namespace TMDbLib.Client } } - public void Dispose() + public virtual void Dispose() { _client?.Dispose(); } diff --git a/TMDbLib/Client/TMDbClientAuthentication.cs b/TMDbLib/Client/TMDbClientAuthentication.cs index 1d7b39d..ba76409 100644 --- a/TMDbLib/Client/TMDbClientAuthentication.cs +++ b/TMDbLib/Client/TMDbClientAuthentication.cs @@ -26,7 +26,7 @@ namespace TMDbLib.Client RestRequest request = _client.Create("authentication/session/new"); request.AddParameter("request_token", initialRequestToken); - RestResponse response = await request.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await request.Get(cancellationToken).ConfigureAwait(false); if (response.StatusCode == HttpStatusCode.Unauthorized) throw new UnauthorizedAccessException(); @@ -51,7 +51,7 @@ namespace TMDbLib.Client { RestRequest request = _client.Create("authentication/token/new"); - RestResponse response = await request.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await request.Get(cancellationToken).ConfigureAwait(false); Token token = await response.GetDataObject().ConfigureAwait(false); token.AuthenticationCallback = response.GetHeader("Authentication-Callback"); @@ -76,6 +76,8 @@ namespace TMDbLib.Client throw ex.InnerException; } + using RestResponse _ = response; + if (response.StatusCode == HttpStatusCode.Unauthorized) { throw new UnauthorizedAccessException("Call to TMDb returned unauthorized. Most likely the provided user credentials are invalid."); diff --git a/TMDbLib/Client/TMDbClientChanges.cs b/TMDbLib/Client/TMDbClientChanges.cs index 56d4cc8..d638054 100644 --- a/TMDbLib/Client/TMDbClientChanges.cs +++ b/TMDbLib/Client/TMDbClientChanges.cs @@ -31,7 +31,7 @@ namespace TMDbLib.Client if (endDate != null) req.AddParameter("end_date", endDate.Value.ToString("yyyy-MM-dd")); - RestResponse resp = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse resp = await req.Get(cancellationToken).ConfigureAwait(false); T res = await resp.GetDataObject().ConfigureAwait(false); if (res is SearchContainer asSearch) diff --git a/TMDbLib/Client/TMDbClientCollections.cs b/TMDbLib/Client/TMDbClientCollections.cs index ebb865c..8710452 100644 --- a/TMDbLib/Client/TMDbClientCollections.cs +++ b/TMDbLib/Client/TMDbClientCollections.cs @@ -56,7 +56,7 @@ namespace TMDbLib.Client //req.DateFormat = "yyyy-MM-dd"; - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); if (!response.IsValid) return null; diff --git a/TMDbLib/Client/TMDbClientConfiguration.cs b/TMDbLib/Client/TMDbClientConfiguration.cs index fe882b1..3511138 100644 --- a/TMDbLib/Client/TMDbClientConfiguration.cs +++ b/TMDbLib/Client/TMDbClientConfiguration.cs @@ -17,7 +17,7 @@ namespace TMDbLib.Client { RestRequest req = _client.Create("configuration"); - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); return (await response.GetDataObject().ConfigureAwait(false)); } @@ -26,16 +26,16 @@ namespace TMDbLib.Client { RestRequest req = _client.Create("configuration/countries"); - RestResponse> response = await req.Get>(cancellationToken).ConfigureAwait(false); + using RestResponse> response = await req.Get>(cancellationToken).ConfigureAwait(false); - return (await response.GetDataObject().ConfigureAwait(false)); + return await response.GetDataObject().ConfigureAwait(false); } public async Task> GetLanguagesAsync(CancellationToken cancellationToken = default) { RestRequest req = _client.Create("configuration/languages"); - RestResponse> response = await req.Get>(cancellationToken).ConfigureAwait(false); + using RestResponse> response = await req.Get>(cancellationToken).ConfigureAwait(false); return (await response.GetDataObject().ConfigureAwait(false)); } @@ -44,7 +44,7 @@ namespace TMDbLib.Client { RestRequest req = _client.Create("configuration/primary_translations"); - RestResponse> response = await req.Get>(cancellationToken).ConfigureAwait(false); + using RestResponse> response = await req.Get>(cancellationToken).ConfigureAwait(false); return (await response.GetDataObject().ConfigureAwait(false)); } @@ -53,7 +53,7 @@ namespace TMDbLib.Client { RestRequest req = _client.Create("timezones/list"); - RestResponse>>> resp = await req.Get>>>(cancellationToken).ConfigureAwait(false); + using RestResponse>>> resp = await req.Get>>>(cancellationToken).ConfigureAwait(false); List>> item = await resp.GetDataObject().ConfigureAwait(false); @@ -81,7 +81,7 @@ namespace TMDbLib.Client { RestRequest req = _client.Create("configuration/jobs"); - RestResponse> response = await req.Get>(cancellationToken).ConfigureAwait(false); + using RestResponse> response = await req.Get>(cancellationToken).ConfigureAwait(false); return (await response.GetDataObject().ConfigureAwait(false)); } diff --git a/TMDbLib/Client/TMDbClientGenres.cs b/TMDbLib/Client/TMDbClientGenres.cs index 57c97cf..729df15 100644 --- a/TMDbLib/Client/TMDbClientGenres.cs +++ b/TMDbLib/Client/TMDbClientGenres.cs @@ -50,7 +50,7 @@ namespace TMDbLib.Client if (!string.IsNullOrWhiteSpace(language)) req.AddParameter("language", language); - RestResponse resp = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse resp = await req.Get(cancellationToken).ConfigureAwait(false); return (await resp.GetDataObject().ConfigureAwait(false)).Genres; } @@ -68,7 +68,7 @@ namespace TMDbLib.Client if (!string.IsNullOrWhiteSpace(language)) req.AddParameter("language", language); - RestResponse resp = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse resp = await req.Get(cancellationToken).ConfigureAwait(false); return (await resp.GetDataObject().ConfigureAwait(false)).Genres; } diff --git a/TMDbLib/Client/TMDbClientLists.cs b/TMDbLib/Client/TMDbClientLists.cs index 28203b2..baa6e6b 100644 --- a/TMDbLib/Client/TMDbClientLists.cs +++ b/TMDbLib/Client/TMDbClientLists.cs @@ -28,7 +28,7 @@ namespace TMDbLib.Client req.SetBody(new { media_id = movieId }); - RestResponse response = await req.Post(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Post(cancellationToken).ConfigureAwait(false); // Status code 12 = "The item/record was updated successfully" // Status code 13 = "The item/record was deleted successfully" @@ -79,7 +79,7 @@ namespace TMDbLib.Client req.AddUrlSegment("listId", listId); req.AddParameter("movie_id", movieId.ToString()); - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); return (await response.GetDataObject().ConfigureAwait(false)).ItemPresent; } @@ -118,7 +118,7 @@ namespace TMDbLib.Client request.AddParameter("confirm", "true"); AddSessionId(request, SessionType.UserSession); - RestResponse response = await request.Post(cancellationToken).ConfigureAwait(false); + using RestResponse response = await request.Post(cancellationToken).ConfigureAwait(false); // Status code 12 = "The item/record was updated successfully" PostReply item = await response.GetDataObject().ConfigureAwait(false); @@ -161,7 +161,7 @@ namespace TMDbLib.Client req.SetBody(new { name = name, description = description }); } - RestResponse response = await req.Post(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Post(cancellationToken).ConfigureAwait(false); return (await response.GetDataObject().ConfigureAwait(false)).ListId; } @@ -184,7 +184,7 @@ namespace TMDbLib.Client req.AddUrlSegment("listId", listId); AddSessionId(req, SessionType.UserSession); - RestResponse response = await req.Delete(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Delete(cancellationToken).ConfigureAwait(false); // Status code 13 = success PostReply item = await response.GetDataObject().ConfigureAwait(false); diff --git a/TMDbLib/Client/TMDbClientMovies.cs b/TMDbLib/Client/TMDbClientMovies.cs index 9d30069..ea7a99f 100644 --- a/TMDbLib/Client/TMDbClientMovies.cs +++ b/TMDbLib/Client/TMDbClientMovies.cs @@ -64,7 +64,7 @@ namespace TMDbLib.Client req.AddUrlSegment("method", MovieMethods.AccountStates.GetDescription()); AddSessionId(req, SessionType.UserSession); - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); return await response.GetDataObject().ConfigureAwait(false); } @@ -132,7 +132,7 @@ namespace TMDbLib.Client if (appends != string.Empty) req.AddParameter("append_to_response", appends); - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); if (!response.IsValid) return null; @@ -203,7 +203,7 @@ namespace TMDbLib.Client public async Task GetMovieLatestAsync(CancellationToken cancellationToken = default) { RestRequest req = _client.Create("movie/latest"); - RestResponse resp = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse resp = await req.Get(cancellationToken).ConfigureAwait(false); Movie item = await resp.GetDataObject().ConfigureAwait(false); @@ -351,7 +351,7 @@ namespace TMDbLib.Client req.AddUrlSegment("movieId", movieId.ToString(CultureInfo.InvariantCulture)); AddSessionId(req); - RestResponse response = await req.Delete(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Delete(cancellationToken).ConfigureAwait(false); // status code 13 = "The item/record was deleted successfully." PostReply item = await response.GetDataObject().ConfigureAwait(false); @@ -379,7 +379,7 @@ namespace TMDbLib.Client req.SetBody(new { value = rating }); - RestResponse response = await req.Post(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Post(cancellationToken).ConfigureAwait(false); // status code 1 = "Success" // status code 12 = "The item/record was updated successfully" - Used when an item was previously rated by the user diff --git a/TMDbLib/Client/TMDbClientPeople.cs b/TMDbLib/Client/TMDbClientPeople.cs index 9b40f3f..57ef0c0 100644 --- a/TMDbLib/Client/TMDbClientPeople.cs +++ b/TMDbLib/Client/TMDbClientPeople.cs @@ -80,7 +80,7 @@ namespace TMDbLib.Client // TODO: Dateformat? //req.DateFormat = "yyyy-MM-dd"; - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); if (!response.IsValid) return null; diff --git a/TMDbLib/Client/TMDbClientTvEpisodeGroups.cs b/TMDbLib/Client/TMDbClientTvEpisodeGroups.cs index a86a4d8..0cc070d 100644 --- a/TMDbLib/Client/TMDbClientTvEpisodeGroups.cs +++ b/TMDbLib/Client/TMDbClientTvEpisodeGroups.cs @@ -23,7 +23,7 @@ namespace TMDbLib.Client if (!string.IsNullOrWhiteSpace(language)) req.AddParameter("language", language); - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); if (!response.IsValid) return null; diff --git a/TMDbLib/Client/TMDbClientTvEpisodes.cs b/TMDbLib/Client/TMDbClientTvEpisodes.cs index f951b41..f29a48b 100644 --- a/TMDbLib/Client/TMDbClientTvEpisodes.cs +++ b/TMDbLib/Client/TMDbClientTvEpisodes.cs @@ -46,7 +46,7 @@ namespace TMDbLib.Client req.AddUrlSegment("method", TvEpisodeMethods.AccountStates.GetDescription()); AddSessionId(req, SessionType.UserSession); - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); return await response.GetDataObject().ConfigureAwait(false); } @@ -92,7 +92,7 @@ namespace TMDbLib.Client if (appends != string.Empty) req.AddParameter("append_to_response", appends); - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); if (!response.IsValid) return null; @@ -184,7 +184,7 @@ namespace TMDbLib.Client AddSessionId(req); - RestResponse response = await req.Delete(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Delete(cancellationToken).ConfigureAwait(false); // status code 13 = "The item/record was deleted successfully." PostReply item = await response.GetDataObject().ConfigureAwait(false); @@ -206,7 +206,7 @@ namespace TMDbLib.Client req.SetBody(new { value = rating }); - RestResponse response = await req.Post(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Post(cancellationToken).ConfigureAwait(false); // status code 1 = "Success" // status code 12 = "The item/record was updated successfully" - Used when an item was previously rated by the user diff --git a/TMDbLib/Client/TMDbClientTvSeasons.cs b/TMDbLib/Client/TMDbClientTvSeasons.cs index 92ae331..f793888 100644 --- a/TMDbLib/Client/TMDbClientTvSeasons.cs +++ b/TMDbLib/Client/TMDbClientTvSeasons.cs @@ -44,7 +44,7 @@ namespace TMDbLib.Client req.AddUrlSegment("method", TvEpisodeMethods.AccountStates.GetDescription()); AddSessionId(req, SessionType.UserSession); - RestResponse> response = await req.Get>(cancellationToken).ConfigureAwait(false); + using RestResponse> response = await req.Get>(cancellationToken).ConfigureAwait(false); return await response.GetDataObject().ConfigureAwait(false); } @@ -89,7 +89,7 @@ namespace TMDbLib.Client if (appends != string.Empty) req.AddParameter("append_to_response", appends); - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); if (!response.IsValid) return null; diff --git a/TMDbLib/Client/TMDbClientTvShows.cs b/TMDbLib/Client/TMDbClientTvShows.cs index 77a2270..209624a 100644 --- a/TMDbLib/Client/TMDbClientTvShows.cs +++ b/TMDbLib/Client/TMDbClientTvShows.cs @@ -85,7 +85,7 @@ namespace TMDbLib.Client req.AddUrlSegment("method", TvShowMethods.AccountStates.GetDescription()); AddSessionId(req, SessionType.UserSession); - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); return await response.GetDataObject().ConfigureAwait(false); } @@ -132,7 +132,7 @@ namespace TMDbLib.Client if (appends != string.Empty) req.AddParameter("append_to_response", appends); - RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); if (!response.IsValid) return null; @@ -210,6 +210,7 @@ namespace TMDbLib.Client /// If specified the api will attempt to return a localized result. ex: en,it,es. /// For images this means that the image might contain language specifc text /// + /// If you want to include a fallback language (especially useful for backdrops) you can use the include_image_language parameter. This should be a comma separated value like so: include_image_language=en,null. /// A cancellation token public async Task GetTvShowImagesAsync(int id, string language = null, string includeImageLanguage = null, CancellationToken cancellationToken = default) { @@ -335,7 +336,7 @@ namespace TMDbLib.Client req.AddUrlSegment("tvShowId", tvShowId.ToString(CultureInfo.InvariantCulture)); AddSessionId(req); - RestResponse response = await req.Delete(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Delete(cancellationToken).ConfigureAwait(false); // status code 13 = "The item/record was deleted successfully." PostReply item = await response.GetDataObject().ConfigureAwait(false); @@ -363,7 +364,7 @@ namespace TMDbLib.Client req.SetBody(new { value = rating }); - RestResponse response = await req.Post(cancellationToken).ConfigureAwait(false); + using RestResponse response = await req.Post(cancellationToken).ConfigureAwait(false); // status code 1 = "Success" // status code 12 = "The item/record was updated successfully" - Used when an item was previously rated by the user diff --git a/TMDbLib/Rest/RestClient.cs b/TMDbLib/Rest/RestClient.cs index 1f6fff7..7fd47ee 100644 --- a/TMDbLib/Rest/RestClient.cs +++ b/TMDbLib/Rest/RestClient.cs @@ -7,7 +7,7 @@ using TMDbLib.Utilities.Serializer; namespace TMDbLib.Rest { - internal class RestClient : IDisposable + internal sealed class RestClient : IDisposable { private int _maxRetryCount; diff --git a/TMDbLib/Rest/RestRequest.cs b/TMDbLib/Rest/RestRequest.cs index fcbca3b..3b2ee41 100644 --- a/TMDbLib/Rest/RestRequest.cs +++ b/TMDbLib/Rest/RestRequest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -93,6 +94,7 @@ namespace TMDbLib.Rest return new RestResponse(resp); } + [SuppressMessage("IDisposableAnalyzers.Correctness", "IDISP001:Dispose created", Justification = "resp is disposed by RestResponse<>()")] public async Task> Delete(CancellationToken cancellationToken) { HttpResponseMessage resp = await SendInternal(HttpMethod.Delete, cancellationToken).ConfigureAwait(false); @@ -107,6 +109,7 @@ namespace TMDbLib.Rest return new RestResponse(resp); } + [SuppressMessage("IDisposableAnalyzers.Correctness", "IDISP001:Dispose created", Justification = "resp is disposed by RestResponse<>()")] public async Task> Get(CancellationToken cancellationToken) { HttpResponseMessage resp = await SendInternal(HttpMethod.Get, cancellationToken).ConfigureAwait(false); @@ -121,6 +124,7 @@ namespace TMDbLib.Rest return new RestResponse(resp); } + [SuppressMessage("IDisposableAnalyzers.Correctness", "IDISP001:Dispose created", Justification = "resp is disposed by RestResponse<>()")] public async Task> Post(CancellationToken cancellationToken) { HttpResponseMessage resp = await SendInternal(HttpMethod.Post, cancellationToken).ConfigureAwait(false); @@ -182,51 +186,49 @@ namespace TMDbLib.Rest do { - using (HttpRequestMessage req = PrepRequest(method)) + using HttpRequestMessage req = PrepRequest(method); + using HttpResponseMessage resp = await _client.HttpClient.SendAsync(req, cancellationToken).ConfigureAwait(false); + + bool isJson = resp.Content.Headers.ContentType.MediaType.Equals("application/json"); + + if (resp.IsSuccessStatusCode && isJson) + return resp; + + if (isJson) + statusMessage = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync().ConfigureAwait(false)); + else + statusMessage = null; + + switch (resp.StatusCode) { - HttpResponseMessage resp = await _client.HttpClient.SendAsync(req, cancellationToken).ConfigureAwait(false); + case (HttpStatusCode)429: + // The previous result was a ratelimit, read the Retry-After header and wait the allotted time + retryHeader = resp.Headers.RetryAfter; + TimeSpan? retryAfter = retryHeader?.Delta.Value; - bool isJson = resp.Content.Headers.ContentType.MediaType.Equals("application/json"); + if (retryAfter.HasValue && retryAfter.Value.TotalSeconds > 0) + await Task.Delay(retryAfter.Value, cancellationToken).ConfigureAwait(false); + else + // TMDb sometimes gives us 0-second waits, which can lead to rapid succession of requests + await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); - if (resp.IsSuccessStatusCode && isJson) - return resp; + continue; + case HttpStatusCode.Unauthorized: + throw new UnauthorizedAccessException( + "Call to TMDb returned unauthorized. Most likely the provided API key is invalid."); - if (isJson) - statusMessage = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync().ConfigureAwait(false)); - else - statusMessage = null; - - switch (resp.StatusCode) - { - case (HttpStatusCode)429: - // The previous result was a ratelimit, read the Retry-After header and wait the allotted time - retryHeader = resp.Headers.RetryAfter; - TimeSpan? retryAfter = retryHeader?.Delta.Value; - - if (retryAfter.HasValue && retryAfter.Value.TotalSeconds > 0) - await Task.Delay(retryAfter.Value, cancellationToken).ConfigureAwait(false); - else - // TMDb sometimes gives us 0-second waits, which can lead to rapid succession of requests - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); - - continue; - case HttpStatusCode.Unauthorized: - throw new UnauthorizedAccessException( - "Call to TMDb returned unauthorized. Most likely the provided API key is invalid."); - - case HttpStatusCode.NotFound: - if (_client.ThrowApiExceptions) - { - throw new NotFoundException(statusMessage); - } - else - { - return null; - } - } - - throw new GeneralHttpException(resp.StatusCode); + case HttpStatusCode.NotFound: + if (_client.ThrowApiExceptions) + { + throw new NotFoundException(statusMessage); + } + else + { + return null; + } } + + throw new GeneralHttpException(resp.StatusCode); } while (timesToTry-- > 0); // We never reached a success diff --git a/TMDbLib/Rest/RestRequestExtensions.cs b/TMDbLib/Rest/RestRequestExtensions.cs index 066d0d6..20cbc4a 100644 --- a/TMDbLib/Rest/RestRequestExtensions.cs +++ b/TMDbLib/Rest/RestRequestExtensions.cs @@ -7,7 +7,7 @@ namespace TMDbLib.Rest { public static async Task DeleteOfT(this RestRequest request, CancellationToken cancellationToken) { - RestResponse resp = await request.Delete(cancellationToken).ConfigureAwait(false); + using RestResponse resp = await request.Delete(cancellationToken).ConfigureAwait(false); if (!resp.IsValid) return default; @@ -17,7 +17,7 @@ namespace TMDbLib.Rest public static async Task GetOfT(this RestRequest request, CancellationToken cancellationToken) { - RestResponse resp = await request.Get(cancellationToken).ConfigureAwait(false); + using RestResponse resp = await request.Get(cancellationToken).ConfigureAwait(false); if (!resp.IsValid) return default; @@ -27,7 +27,7 @@ namespace TMDbLib.Rest public static async Task PostOfT(this RestRequest request, CancellationToken cancellationToken) { - RestResponse resp = await request.Post(cancellationToken).ConfigureAwait(false); + using RestResponse resp = await request.Post(cancellationToken).ConfigureAwait(false); if (!resp.IsValid) return default; diff --git a/TMDbLib/Rest/RestResponse.cs b/TMDbLib/Rest/RestResponse.cs index 9ce9cd4..513d45e 100644 --- a/TMDbLib/Rest/RestResponse.cs +++ b/TMDbLib/Rest/RestResponse.cs @@ -1,3 +1,5 @@ +using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Net; @@ -7,9 +9,9 @@ using TMDbLib.Utilities.Serializer; namespace TMDbLib.Rest { - internal class RestResponse + internal class RestResponse :IDisposable { - protected readonly HttpResponseMessage Response; + private readonly HttpResponseMessage Response; public RestResponse(HttpResponseMessage response) { @@ -29,6 +31,12 @@ namespace TMDbLib.Rest { return Response.Headers.GetValues(name).FirstOrDefault() ?? @default; } + + [SuppressMessage("IDisposableAnalyzers.Correctness", "IDISP007:Don't dispose injected.", Justification = "RestResponse owns the response")] + public virtual void Dispose() + { + Response.Dispose(); + } } internal class RestResponse : RestResponse diff --git a/TMDbLib/Utilities/Converters/AccountStateConverter.cs b/TMDbLib/Utilities/Converters/AccountStateConverter.cs index 1b17c39..2bbd620 100644 --- a/TMDbLib/Utilities/Converters/AccountStateConverter.cs +++ b/TMDbLib/Utilities/Converters/AccountStateConverter.cs @@ -46,7 +46,8 @@ namespace TMDbLib.Utilities.Converters object result = Activator.CreateInstance(objectType); // Populate the result - serializer.Populate(jObject.CreateReader(), result); + using JsonReader jsonReader = jObject.CreateReader(); + serializer.Populate(jsonReader, result); return result; } diff --git a/TMDbLib/Utilities/Converters/ChangeItemConverter.cs b/TMDbLib/Utilities/Converters/ChangeItemConverter.cs index 4b019de..1bff381 100644 --- a/TMDbLib/Utilities/Converters/ChangeItemConverter.cs +++ b/TMDbLib/Utilities/Converters/ChangeItemConverter.cs @@ -50,7 +50,8 @@ namespace TMDbLib.Utilities.Converters } // Populate the result - serializer.Populate(jObject.CreateReader(), result); + using JsonReader jsonReader = jObject.CreateReader(); + serializer.Populate(jsonReader, result); return result; } diff --git a/TMDbLib/Utilities/Converters/JsonCreationConverter.cs b/TMDbLib/Utilities/Converters/JsonCreationConverter.cs index f396ba1..ac8a257 100644 --- a/TMDbLib/Utilities/Converters/JsonCreationConverter.cs +++ b/TMDbLib/Utilities/Converters/JsonCreationConverter.cs @@ -13,7 +13,9 @@ namespace TMDbLib.Utilities.Converters JObject jObject = JObject.Load(reader); T target = GetInstance(jObject); - serializer.Populate(jObject.CreateReader(), target); + + using JsonReader jsonReader = jObject.CreateReader(); + serializer.Populate(jsonReader, target); return target; } diff --git a/TMDbLib/Utilities/Converters/SearchBaseConverter.cs b/TMDbLib/Utilities/Converters/SearchBaseConverter.cs index 4a7291a..84d0bd7 100644 --- a/TMDbLib/Utilities/Converters/SearchBaseConverter.cs +++ b/TMDbLib/Utilities/Converters/SearchBaseConverter.cs @@ -48,7 +48,8 @@ namespace TMDbLib.Utilities.Converters } // Populate the result - serializer.Populate(jObject.CreateReader(), result); + using JsonReader jsonReader = jObject.CreateReader(); + serializer.Populate(jsonReader, result); return result; } diff --git a/TMDbLib/Utilities/Converters/TaggedImageConverter.cs b/TMDbLib/Utilities/Converters/TaggedImageConverter.cs index cd87008..d57103b 100644 --- a/TMDbLib/Utilities/Converters/TaggedImageConverter.cs +++ b/TMDbLib/Utilities/Converters/TaggedImageConverter.cs @@ -19,7 +19,9 @@ namespace TMDbLib.Utilities.Converters JObject jObject = JObject.Load(reader); TaggedImage result = new TaggedImage(); - serializer.Populate(jObject.CreateReader(), result); + + using (JsonReader jsonReader = jObject.CreateReader()) + serializer.Populate(jsonReader, result); JToken mediaJson = jObject["media"]; switch (result.MediaType) diff --git a/TMDbLibTests/ClientGenreTests.cs b/TMDbLibTests/ClientGenreTests.cs index dd47396..a81d640 100644 --- a/TMDbLibTests/ClientGenreTests.cs +++ b/TMDbLibTests/ClientGenreTests.cs @@ -58,11 +58,13 @@ namespace TMDbLibTests [Fact] public async Task TestGenreMoviesAsync() { +#pragma warning disable CS0618 // Type or member is obsolete SearchContainerWithId movies = await TMDbClient.GetGenreMoviesAsync(IdHelper.AdventureMovieGenre); Assert.NotEmpty(movies.Results); Assert.Equal(IdHelper.AdventureMovieGenre, movies.Id); Assert.All(movies.Results, x => Assert.Contains(IdHelper.AdventureMovieGenre, x.GenreIds)); +#pragma warning restore CS0618 // Type or member is obsolete } } } diff --git a/TMDbLibTests/JsonHelpers/TestBase.cs b/TMDbLibTests/JsonHelpers/TestBase.cs index 2cca122..d674c44 100644 --- a/TMDbLibTests/JsonHelpers/TestBase.cs +++ b/TMDbLibTests/JsonHelpers/TestBase.cs @@ -163,8 +163,8 @@ namespace TMDbLibTests.JsonHelpers public int Compare(object x, object y) { - object? valX = _property.GetValue(x); - object? valY = _property.GetValue(y); + object valX = _property.GetValue(x); + object valY = _property.GetValue(y); return Comparer.Default.Compare(valX, valY); }