Skip to content

Added support for cancellation tokens#178

Open
euantorano wants to merge 3 commits into
alphagov:mainfrom
euantorano:feature/cancellation-support
Open

Added support for cancellation tokens#178
euantorano wants to merge 3 commits into
alphagov:mainfrom
euantorano:feature/cancellation-support

Conversation

@euantorano

@euantorano euantorano commented Sep 27, 2023

Copy link
Copy Markdown

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 be awaited.

These changes allow early cancellation of requests.

Checklist

  • I’ve used the pull request template
  • I’ve written unit tests for these changes
  • I’ve update the documentation (in DOCUMENATION.md and CHANGELOG.md)
  • I’ve bumped the version number (in src/GovukNotify/GovukNotify.csproj)

this.client.AddContentHeader("application/json");

var productVersion = typeof(BaseClient).GetTypeInfo().Assembly.GetName().Version.ToString();
var productVersion = typeof(BaseClient).GetTypeInfo().Assembly.GetName().Version?.ToString();

Copy link
Copy Markdown
Author

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.

Comment on lines +64 to +70
#if NET6_0_OR_GREATER
var responseContent = await response.Content.ReadAsByteArrayAsync(cancellationToken)
.ConfigureAwait(false);
#else
var responseContent = await response.Content.ReadAsByteArrayAsync()
.ConfigureAwait(false);
#endif

Copy link
Copy Markdown
Author

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.

Comment on lines +86 to +92
#if NET6_0_OR_GREATER
var responseContent = await response.Content.ReadAsStringAsync(cancellationToken)
.ConfigureAwait(false);
#else
var responseContent = await response.Content.ReadAsStringAsync()
.ConfigureAwait(false);
#endif

Copy link
Copy Markdown
Author

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.

if (x is HttpRequestException)
{
throw new NotifyClientException(x.InnerException.Message);
throw new NotifyClientException(x.InnerException?.Message ?? x.Message);

Copy link
Copy Markdown
Author

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.

Comment on lines +151 to +153
if (string.IsNullOrWhiteSpace(fromApiKey) || fromApiKey.Length < 74 || fromApiKey.Contains(' '))
#else
if (string.IsNullOrWhiteSpace(fromApiKey) || fromApiKey.Length < 74 || fromApiKey.Contains(" "))

@euantorano euantorano Sep 27, 2023

Copy link
Copy Markdown
Author

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 NullReferenceExceptions when an api key was not set.

Comment on lines 33 to 52
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;
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

if (ex.InnerExceptions != null && ex.InnerExceptions.Count == 1)
if (ex.InnerExceptions.Count == 1)

Copy link
Copy Markdown
Author

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.

@euantorano euantorano marked this pull request as ready for review September 27, 2023 11:40
@euantorano

Copy link
Copy Markdown
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cancellation support for async methods Task result obtained synchronously inside an asynchronous method

1 participant