From 1a39b3e2770d05a2528bd4d95ff8b9669de9a1d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C4=99czek?= Date: Sun, 20 Feb 2022 18:19:40 +0100 Subject: [PATCH] Adding request cancellation to Desktop .NET scenario (#6) --- Demo.Ndjson.AsyncStreams.Net.Http/Program.cs | 70 +++++++++++++------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/Demo.Ndjson.AsyncStreams.Net.Http/Program.cs b/Demo.Ndjson.AsyncStreams.Net.Http/Program.cs index 5bc372b..1cca796 100644 --- a/Demo.Ndjson.AsyncStreams.Net.Http/Program.cs +++ b/Demo.Ndjson.AsyncStreams.Net.Http/Program.cs @@ -4,8 +4,10 @@ using System.Buffers; using System.Net.Http; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Ndjson.AsyncStreams.Net.Http; using Demo.WeatherForecasts; @@ -17,32 +19,54 @@ class Program static async Task Main(string[] args) { - await ConsumeNdjsonStreamAsync().ConfigureAwait(false); + using CancellationTokenSource cancellationTokenSource = new(); - await NegotiateRawJsonStreamAsync().ConfigureAwait(false); + void consoleCancelEventHandler(object sender, ConsoleCancelEventArgs eventArgs) + { + Console.WriteLine("Attempting to cancel . . ."); + + cancellationTokenSource.Cancel(); + eventArgs.Cancel = true; + }; + Console.CancelKeyPress += consoleCancelEventHandler; + + CancellationToken cancellationToken = cancellationTokenSource.Token; + + try + { + //await ConsumeNdjsonStreamAsync(cancellationToken).ConfigureAwait(false); - await NegotiateJsonStreamAsync().ConfigureAwait(false); + //await NegotiateRawJsonStreamAsync(cancellationToken).ConfigureAwait(false); - await NegotiateNdjsonStreamAsync().ConfigureAwait(false); + //await NegotiateJsonStreamAsync(cancellationToken).ConfigureAwait(false); - await StreamNdjsonAsync().ConfigureAwait(false); + //await NegotiateNdjsonStreamAsync(cancellationToken).ConfigureAwait(false); - Console.WriteLine("Press any key to exit . . ."); - Console.ReadKey(true); + await StreamNdjsonAsync(cancellationToken).ConfigureAwait(false); + + Console.CancelKeyPress -= consoleCancelEventHandler; + + Console.WriteLine("Press any key to exit . . ."); + Console.ReadKey(true); + } + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) + { + Console.WriteLine("Successfully cancelled."); + } } - private static async Task ConsumeNdjsonStreamAsync() + private static async Task ConsumeNdjsonStreamAsync(CancellationToken cancellationToken) { Console.WriteLine($"-- {nameof(ConsumeNdjsonStreamAsync)} --"); Console.WriteLine($"[{DateTime.UtcNow:hh:mm:ss.fff}] Receving weather forecasts . . ."); using HttpClient httpClient = new(); - using HttpResponseMessage response = await httpClient.GetAsync("https://localhost:5001/api/WeatherForecasts/stream", HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false); + using HttpResponseMessage response = await httpClient.GetAsync("https://localhost:5001/api/WeatherForecasts/stream", HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); - await foreach (WeatherForecast weatherForecast in response.Content!.ReadFromNdjsonAsync().ConfigureAwait(false)) + await foreach (WeatherForecast weatherForecast in response.Content!.ReadFromNdjsonAsync(cancellationToken: cancellationToken).ConfigureAwait(false)) { Console.WriteLine($"[{DateTime.UtcNow:hh:mm:ss.fff}] {weatherForecast.Summary}"); } @@ -51,7 +75,7 @@ private static async Task ConsumeNdjsonStreamAsync() Console.WriteLine(); } - private static async Task NegotiateRawJsonStreamAsync() + private static async Task NegotiateRawJsonStreamAsync(CancellationToken cancellationToken) { Console.WriteLine($"-- {nameof(NegotiateRawJsonStreamAsync)} --"); Console.WriteLine($"[{DateTime.UtcNow:hh:mm:ss.fff}] Receving weather forecasts . . ."); @@ -59,15 +83,15 @@ private static async Task NegotiateRawJsonStreamAsync() using HttpClient httpClient = new(); httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); - using HttpResponseMessage response = await httpClient.GetAsync("https://localhost:5001/api/WeatherForecasts/negotiate-stream", HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false); + using HttpResponseMessage response = await httpClient.GetAsync("https://localhost:5001/api/WeatherForecasts/negotiate-stream", HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); - using Stream responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + using Stream responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); while (true) { byte[] buffer = ArrayPool.Shared.Rent(128); - int bytesRead = await responseStream.ReadAsync(buffer); + int bytesRead = await responseStream.ReadAsync(buffer, cancellationToken); Console.WriteLine($"[{DateTime.UtcNow:hh:mm:ss.fff}] ({bytesRead}/{buffer.Length}) {Encoding.UTF8.GetString(buffer)}"); @@ -83,7 +107,7 @@ private static async Task NegotiateRawJsonStreamAsync() Console.WriteLine(); } - private static async Task NegotiateJsonStreamAsync() + private static async Task NegotiateJsonStreamAsync(CancellationToken cancellationToken) { Console.WriteLine($"-- {nameof(NegotiateJsonStreamAsync)} --"); Console.WriteLine($"[{DateTime.UtcNow:hh:mm:ss.fff}] Receving weather forecasts . . ."); @@ -91,12 +115,12 @@ private static async Task NegotiateJsonStreamAsync() using HttpClient httpClient = new(); httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); - using HttpResponseMessage response = await httpClient.GetAsync("https://localhost:5001/api/WeatherForecasts/negotiate-stream", HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false); + using HttpResponseMessage response = await httpClient.GetAsync("https://localhost:5001/api/WeatherForecasts/negotiate-stream", HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); - using Stream responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + using Stream responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - await foreach (WeatherForecast weatherForecast in JsonSerializer.DeserializeAsyncEnumerable(responseStream, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, DefaultBufferSize = 128 })) + await foreach (WeatherForecast weatherForecast in JsonSerializer.DeserializeAsyncEnumerable(responseStream, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, DefaultBufferSize = 128 }, cancellationToken)) { Console.WriteLine($"[{DateTime.UtcNow:hh:mm:ss.fff}] {weatherForecast.Summary}"); } @@ -105,7 +129,7 @@ private static async Task NegotiateJsonStreamAsync() Console.WriteLine(); } - private static async Task NegotiateNdjsonStreamAsync() + private static async Task NegotiateNdjsonStreamAsync(CancellationToken cancellationToken) { Console.WriteLine($"-- {nameof(NegotiateNdjsonStreamAsync)} --"); Console.WriteLine($"[{DateTime.UtcNow:hh:mm:ss.fff}] Receving weather forecasts . . ."); @@ -113,11 +137,11 @@ private static async Task NegotiateNdjsonStreamAsync() using HttpClient httpClient = new(); httpClient.DefaultRequestHeaders.Add("Accept", "application/x-ndjson"); - using HttpResponseMessage response = await httpClient.GetAsync("https://localhost:5001/api/WeatherForecasts/negotiate-stream", HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false); + using HttpResponseMessage response = await httpClient.GetAsync("https://localhost:5001/api/WeatherForecasts/negotiate-stream", HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); - await foreach (WeatherForecast weatherForecast in response.Content!.ReadFromNdjsonAsync().ConfigureAwait(false)) + await foreach (WeatherForecast weatherForecast in response.Content!.ReadFromNdjsonAsync(cancellationToken: cancellationToken).ConfigureAwait(false)) { Console.WriteLine($"[{DateTime.UtcNow:hh:mm:ss.fff}] {weatherForecast.Summary}"); } @@ -126,7 +150,7 @@ private static async Task NegotiateNdjsonStreamAsync() Console.WriteLine(); } - private static async Task StreamNdjsonAsync() + private static async Task StreamNdjsonAsync(CancellationToken cancellationToken) { static async IAsyncEnumerable streamWeatherForecastsAsync() { @@ -143,7 +167,7 @@ static async IAsyncEnumerable streamWeatherForecastsAsync() using HttpClient httpClient = new(); - using HttpResponseMessage response = await httpClient.PostAsNdjsonAsync("https://localhost:5001/api/WeatherForecasts/stream", streamWeatherForecastsAsync()).ConfigureAwait(false); + using HttpResponseMessage response = await httpClient.PostAsNdjsonAsync("https://localhost:5001/api/WeatherForecasts/stream", streamWeatherForecastsAsync(), cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode();