-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added support for cancellation tokens #178
base: main
Are you sure you want to change the base?
Conversation
…gov#130 - await rather than accessing task result.
@@ -34,55 +35,71 @@ public BaseClient(IHttpClient client, string apiKey, string baseUrl = "https://a | |||
this.client.BaseAddress = ValidateBaseUri(BaseUrl); | |||
this.client.AddContentHeader("application/json"); | |||
|
|||
var productVersion = typeof(BaseClient).GetTypeInfo().Assembly.GetName().Version.ToString(); | |||
var productVersion = typeof(BaseClient).GetTypeInfo().Assembly.GetName().Version?.ToString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is required as there was the possibility of a NullReferenceException
in the original code - the Version
attribute may be null.
If nullable types were enabled for the project it would likely help catch other similar problems.
#if NET6_0_OR_GREATER | ||
var responseContent = await response.Content.ReadAsByteArrayAsync(cancellationToken) | ||
.ConfigureAwait(false); | ||
#else | ||
var responseContent = await response.Content.ReadAsByteArrayAsync() | ||
.ConfigureAwait(false); | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing cancellation tokens when reading content is only supported in .NET standard 2.1 and up. This project currently targets .net standard 2.0 and .net 6, so this conditional compilation should work.
#if NET6_0_OR_GREATER | ||
var responseContent = await response.Content.ReadAsStringAsync(cancellationToken) | ||
.ConfigureAwait(false); | ||
#else | ||
var responseContent = await response.Content.ReadAsStringAsync() | ||
.ConfigureAwait(false); | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, as before this conditional compilation is required due to the target framework.
} | ||
catch (AggregateException ae) | ||
{ | ||
ae.Handle(x => | ||
{ | ||
if (x is HttpRequestException) | ||
{ | ||
throw new NotifyClientException(x.InnerException.Message); | ||
throw new NotifyClientException(x.InnerException?.Message ?? x.Message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's possible for InnerException
to be null here, which would lead to an uncaught NullReferenceException
.
if (string.IsNullOrWhiteSpace(fromApiKey) || fromApiKey.Length < 74 || fromApiKey.Contains(' ')) | ||
#else | ||
if (string.IsNullOrWhiteSpace(fromApiKey) || fromApiKey.Length < 74 || fromApiKey.Contains(" ")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the original code the .Length
property was accessed before checking for null, which led to NullReferenceException
s when an api key was not set.
public void Dispose() | ||
{ | ||
_client.Dispose(); | ||
Dispose(true); | ||
GC.SuppressFinalize(this); | ||
} | ||
|
||
protected virtual void Dispose(bool disposing) | ||
{ | ||
if (_disposed) | ||
{ | ||
return; | ||
} | ||
|
||
if (disposing) | ||
{ | ||
_client.Dispose(); | ||
} | ||
|
||
_disposed = true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is to implement the dispose pattern as recommended by Microsoft:
https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose
https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern
} | ||
|
||
if (ex.InnerExceptions != null && ex.InnerExceptions.Count == 1) | ||
if (ex.InnerExceptions.Count == 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InnerExceptions
cannot be null, so there's no need for a null check here.
I'm not sure why but it looks like the CI may be stalled on this one. Would someone mind giving it a nudge? The changes mentioned in the previous comment will be explored in a future PR after this one has been merged. |
What problem does the pull request solve?
Fixes #176 by adding support for passing
CancellationToken
parameters to asynchronous methods.Also fixes #130 - rather than accessing a
Task
result directly the task should beawait
ed.These changes allow early cancellation of requests.
Checklist
DOCUMENATION.md
andCHANGELOG.md
)src/GovukNotify/GovukNotify.csproj
)