Fixup disposable usage internally, to ensure HttpResponseMessage is disposed

This commit is contained in:
Michael Bisbjerg 2022-01-18 23:27:30 +01:00
parent 2118725348
commit 5edc95e0f6
24 changed files with 113 additions and 89 deletions

View File

@ -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();
}

View File

@ -26,7 +26,7 @@ namespace TMDbLib.Client
RestRequest request = _client.Create("authentication/session/new");
request.AddParameter("request_token", initialRequestToken);
RestResponse<UserSession> response = await request.Get<UserSession>(cancellationToken).ConfigureAwait(false);
using RestResponse<UserSession> response = await request.Get<UserSession>(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<Token> response = await request.Get<Token>(cancellationToken).ConfigureAwait(false);
using RestResponse<Token> response = await request.Get<Token>(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.");

View File

@ -31,7 +31,7 @@ namespace TMDbLib.Client
if (endDate != null)
req.AddParameter("end_date", endDate.Value.ToString("yyyy-MM-dd"));
RestResponse<T> resp = await req.Get<T>(cancellationToken).ConfigureAwait(false);
using RestResponse<T> resp = await req.Get<T>(cancellationToken).ConfigureAwait(false);
T res = await resp.GetDataObject().ConfigureAwait(false);
if (res is SearchContainer<ChangesListItem> asSearch)

View File

@ -56,7 +56,7 @@ namespace TMDbLib.Client
//req.DateFormat = "yyyy-MM-dd";
RestResponse<Collection> response = await req.Get<Collection>(cancellationToken).ConfigureAwait(false);
using RestResponse<Collection> response = await req.Get<Collection>(cancellationToken).ConfigureAwait(false);
if (!response.IsValid)
return null;

View File

@ -17,7 +17,7 @@ namespace TMDbLib.Client
{
RestRequest req = _client.Create("configuration");
RestResponse<APIConfiguration> response = await req.Get<APIConfiguration>(cancellationToken).ConfigureAwait(false);
using RestResponse<APIConfiguration> response = await req.Get<APIConfiguration>(cancellationToken).ConfigureAwait(false);
return (await response.GetDataObject().ConfigureAwait(false));
}
@ -26,16 +26,16 @@ namespace TMDbLib.Client
{
RestRequest req = _client.Create("configuration/countries");
RestResponse<List<Country>> response = await req.Get<List<Country>>(cancellationToken).ConfigureAwait(false);
using RestResponse<List<Country>> response = await req.Get<List<Country>>(cancellationToken).ConfigureAwait(false);
return (await response.GetDataObject().ConfigureAwait(false));
return await response.GetDataObject().ConfigureAwait(false);
}
public async Task<List<Language>> GetLanguagesAsync(CancellationToken cancellationToken = default)
{
RestRequest req = _client.Create("configuration/languages");
RestResponse<List<Language>> response = await req.Get<List<Language>>(cancellationToken).ConfigureAwait(false);
using RestResponse<List<Language>> response = await req.Get<List<Language>>(cancellationToken).ConfigureAwait(false);
return (await response.GetDataObject().ConfigureAwait(false));
}
@ -44,7 +44,7 @@ namespace TMDbLib.Client
{
RestRequest req = _client.Create("configuration/primary_translations");
RestResponse<List<string>> response = await req.Get<List<string>>(cancellationToken).ConfigureAwait(false);
using RestResponse<List<string>> response = await req.Get<List<string>>(cancellationToken).ConfigureAwait(false);
return (await response.GetDataObject().ConfigureAwait(false));
}
@ -53,7 +53,7 @@ namespace TMDbLib.Client
{
RestRequest req = _client.Create("timezones/list");
RestResponse<List<Dictionary<string, List<string>>>> resp = await req.Get<List<Dictionary<string, List<string>>>>(cancellationToken).ConfigureAwait(false);
using RestResponse<List<Dictionary<string, List<string>>>> resp = await req.Get<List<Dictionary<string, List<string>>>>(cancellationToken).ConfigureAwait(false);
List<Dictionary<string, List<string>>> item = await resp.GetDataObject().ConfigureAwait(false);
@ -81,7 +81,7 @@ namespace TMDbLib.Client
{
RestRequest req = _client.Create("configuration/jobs");
RestResponse<List<Job>> response = await req.Get<List<Job>>(cancellationToken).ConfigureAwait(false);
using RestResponse<List<Job>> response = await req.Get<List<Job>>(cancellationToken).ConfigureAwait(false);
return (await response.GetDataObject().ConfigureAwait(false));
}

View File

@ -50,7 +50,7 @@ namespace TMDbLib.Client
if (!string.IsNullOrWhiteSpace(language))
req.AddParameter("language", language);
RestResponse<GenreContainer> resp = await req.Get<GenreContainer>(cancellationToken).ConfigureAwait(false);
using RestResponse<GenreContainer> resp = await req.Get<GenreContainer>(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<GenreContainer> resp = await req.Get<GenreContainer>(cancellationToken).ConfigureAwait(false);
using RestResponse<GenreContainer> resp = await req.Get<GenreContainer>(cancellationToken).ConfigureAwait(false);
return (await resp.GetDataObject().ConfigureAwait(false)).Genres;
}

View File

@ -28,7 +28,7 @@ namespace TMDbLib.Client
req.SetBody(new { media_id = movieId });
RestResponse<PostReply> response = await req.Post<PostReply>(cancellationToken).ConfigureAwait(false);
using RestResponse<PostReply> response = await req.Post<PostReply>(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<ListStatus> response = await req.Get<ListStatus>(cancellationToken).ConfigureAwait(false);
using RestResponse<ListStatus> response = await req.Get<ListStatus>(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<PostReply> response = await request.Post<PostReply>(cancellationToken).ConfigureAwait(false);
using RestResponse<PostReply> response = await request.Post<PostReply>(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<ListCreateReply> response = await req.Post<ListCreateReply>(cancellationToken).ConfigureAwait(false);
using RestResponse<ListCreateReply> response = await req.Post<ListCreateReply>(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<PostReply> response = await req.Delete<PostReply>(cancellationToken).ConfigureAwait(false);
using RestResponse<PostReply> response = await req.Delete<PostReply>(cancellationToken).ConfigureAwait(false);
// Status code 13 = success
PostReply item = await response.GetDataObject().ConfigureAwait(false);

View File

@ -64,7 +64,7 @@ namespace TMDbLib.Client
req.AddUrlSegment("method", MovieMethods.AccountStates.GetDescription());
AddSessionId(req, SessionType.UserSession);
RestResponse<AccountState> response = await req.Get<AccountState>(cancellationToken).ConfigureAwait(false);
using RestResponse<AccountState> response = await req.Get<AccountState>(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<Movie> response = await req.Get<Movie>(cancellationToken).ConfigureAwait(false);
using RestResponse<Movie> response = await req.Get<Movie>(cancellationToken).ConfigureAwait(false);
if (!response.IsValid)
return null;
@ -203,7 +203,7 @@ namespace TMDbLib.Client
public async Task<Movie> GetMovieLatestAsync(CancellationToken cancellationToken = default)
{
RestRequest req = _client.Create("movie/latest");
RestResponse<Movie> resp = await req.Get<Movie>(cancellationToken).ConfigureAwait(false);
using RestResponse<Movie> resp = await req.Get<Movie>(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<PostReply> response = await req.Delete<PostReply>(cancellationToken).ConfigureAwait(false);
using RestResponse<PostReply> response = await req.Delete<PostReply>(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<PostReply> response = await req.Post<PostReply>(cancellationToken).ConfigureAwait(false);
using RestResponse<PostReply> response = await req.Post<PostReply>(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

View File

@ -80,7 +80,7 @@ namespace TMDbLib.Client
// TODO: Dateformat?
//req.DateFormat = "yyyy-MM-dd";
RestResponse<Person> response = await req.Get<Person>(cancellationToken).ConfigureAwait(false);
using RestResponse<Person> response = await req.Get<Person>(cancellationToken).ConfigureAwait(false);
if (!response.IsValid)
return null;

View File

@ -23,7 +23,7 @@ namespace TMDbLib.Client
if (!string.IsNullOrWhiteSpace(language))
req.AddParameter("language", language);
RestResponse<TvGroupCollection> response = await req.Get<TvGroupCollection>(cancellationToken).ConfigureAwait(false);
using RestResponse<TvGroupCollection> response = await req.Get<TvGroupCollection>(cancellationToken).ConfigureAwait(false);
if (!response.IsValid)
return null;

View File

@ -46,7 +46,7 @@ namespace TMDbLib.Client
req.AddUrlSegment("method", TvEpisodeMethods.AccountStates.GetDescription());
AddSessionId(req, SessionType.UserSession);
RestResponse<TvEpisodeAccountState> response = await req.Get<TvEpisodeAccountState>(cancellationToken).ConfigureAwait(false);
using RestResponse<TvEpisodeAccountState> response = await req.Get<TvEpisodeAccountState>(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<TvEpisode> response = await req.Get<TvEpisode>(cancellationToken).ConfigureAwait(false);
using RestResponse<TvEpisode> response = await req.Get<TvEpisode>(cancellationToken).ConfigureAwait(false);
if (!response.IsValid)
return null;
@ -184,7 +184,7 @@ namespace TMDbLib.Client
AddSessionId(req);
RestResponse<PostReply> response = await req.Delete<PostReply>(cancellationToken).ConfigureAwait(false);
using RestResponse<PostReply> response = await req.Delete<PostReply>(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<PostReply> response = await req.Post<PostReply>(cancellationToken).ConfigureAwait(false);
using RestResponse<PostReply> response = await req.Post<PostReply>(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

View File

@ -44,7 +44,7 @@ namespace TMDbLib.Client
req.AddUrlSegment("method", TvEpisodeMethods.AccountStates.GetDescription());
AddSessionId(req, SessionType.UserSession);
RestResponse<ResultContainer<TvEpisodeAccountStateWithNumber>> response = await req.Get<ResultContainer<TvEpisodeAccountStateWithNumber>>(cancellationToken).ConfigureAwait(false);
using RestResponse<ResultContainer<TvEpisodeAccountStateWithNumber>> response = await req.Get<ResultContainer<TvEpisodeAccountStateWithNumber>>(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<TvSeason> response = await req.Get<TvSeason>(cancellationToken).ConfigureAwait(false);
using RestResponse<TvSeason> response = await req.Get<TvSeason>(cancellationToken).ConfigureAwait(false);
if (!response.IsValid)
return null;

View File

@ -85,7 +85,7 @@ namespace TMDbLib.Client
req.AddUrlSegment("method", TvShowMethods.AccountStates.GetDescription());
AddSessionId(req, SessionType.UserSession);
RestResponse<AccountState> response = await req.Get<AccountState>(cancellationToken).ConfigureAwait(false);
using RestResponse<AccountState> response = await req.Get<AccountState>(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<TvShow> response = await req.Get<TvShow>(cancellationToken).ConfigureAwait(false);
using RestResponse<TvShow> response = await req.Get<TvShow>(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
/// </param>
/// <param name="includeImageLanguage">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.</param>
/// <param name="cancellationToken">A cancellation token</param>
public async Task<ImagesWithId> 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<PostReply> response = await req.Delete<PostReply>(cancellationToken).ConfigureAwait(false);
using RestResponse<PostReply> response = await req.Delete<PostReply>(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<PostReply> response = await req.Post<PostReply>(cancellationToken).ConfigureAwait(false);
using RestResponse<PostReply> response = await req.Post<PostReply>(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

View File

@ -7,7 +7,7 @@ using TMDbLib.Utilities.Serializer;
namespace TMDbLib.Rest
{
internal class RestClient : IDisposable
internal sealed class RestClient : IDisposable
{
private int _maxRetryCount;

View File

@ -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<RestResponse<T>> Delete<T>(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<RestResponse<T>> Get<T>(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<RestResponse<T>> Post<T>(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<TMDbStatusMessage>(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<TMDbStatusMessage>(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

View File

@ -7,7 +7,7 @@ namespace TMDbLib.Rest
{
public static async Task<T> DeleteOfT<T>(this RestRequest request, CancellationToken cancellationToken)
{
RestResponse<T> resp = await request.Delete<T>(cancellationToken).ConfigureAwait(false);
using RestResponse<T> resp = await request.Delete<T>(cancellationToken).ConfigureAwait(false);
if (!resp.IsValid)
return default;
@ -17,7 +17,7 @@ namespace TMDbLib.Rest
public static async Task<T> GetOfT<T>(this RestRequest request, CancellationToken cancellationToken)
{
RestResponse<T> resp = await request.Get<T>(cancellationToken).ConfigureAwait(false);
using RestResponse<T> resp = await request.Get<T>(cancellationToken).ConfigureAwait(false);
if (!resp.IsValid)
return default;
@ -27,7 +27,7 @@ namespace TMDbLib.Rest
public static async Task<T> PostOfT<T>(this RestRequest request, CancellationToken cancellationToken)
{
RestResponse<T> resp = await request.Post<T>(cancellationToken).ConfigureAwait(false);
using RestResponse<T> resp = await request.Post<T>(cancellationToken).ConfigureAwait(false);
if (!resp.IsValid)
return default;

View File

@ -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<T> : RestResponse

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -58,11 +58,13 @@ namespace TMDbLibTests
[Fact]
public async Task TestGenreMoviesAsync()
{
#pragma warning disable CS0618 // Type or member is obsolete
SearchContainerWithId<SearchMovie> 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
}
}
}

View File

@ -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);
}