Improve shutdown of SignalR .NET client sample (#10675)

This commit is contained in:
Stephen Halter 2019-06-05 21:31:04 -07:00 committed by GitHub
parent c518cff370
commit 511761627a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 59 additions and 55 deletions

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client; using Microsoft.AspNetCore.SignalR.Client;
@ -29,7 +28,9 @@ namespace ClientSample
public static async Task<int> ExecuteAsync(string baseUrl) public static async Task<int> ExecuteAsync(string baseUrl)
{ {
var uri = baseUrl == null ? new Uri("net.tcp://127.0.0.1:9001") : new Uri(baseUrl); var uri = baseUrl == null ? new Uri("net.tcp://127.0.0.1:9001") : new Uri(baseUrl);
Console.WriteLine("Connecting to {0}", uri); Console.WriteLine("Connecting to {0}", uri);
var connectionBuilder = new HubConnectionBuilder() var connectionBuilder = new HubConnectionBuilder()
.ConfigureLogging(logging => .ConfigureLogging(logging =>
{ {
@ -52,59 +53,58 @@ namespace ClientSample
connectionBuilder.WithAutomaticReconnect(); connectionBuilder.WithAutomaticReconnect();
using var closedTokenSource = new CancellationTokenSource();
var connection = connectionBuilder.Build(); var connection = connectionBuilder.Build();
try
{
Console.CancelKeyPress += (sender, a) => Console.CancelKeyPress += (sender, a) =>
{ {
a.Cancel = true; a.Cancel = true;
connection.DisposeAsync().GetAwaiter().GetResult(); closedTokenSource.Cancel();
connection.StopAsync().GetAwaiter().GetResult();
}; };
// Set up handler // Set up handler
connection.On<string>("Send", Console.WriteLine); connection.On<string>("Send", Console.WriteLine);
CancellationTokenSource closedTokenSource = null;
connection.Closed += e => connection.Closed += e =>
{ {
// This should never be null by the time this fires
closedTokenSource.Cancel();
Console.WriteLine("Connection closed..."); Console.WriteLine("Connection closed...");
closedTokenSource.Cancel();
return Task.CompletedTask; return Task.CompletedTask;
}; };
if (!await ConnectAsync(connection, closedTokenSource.Token))
do
{ {
// Dispose the previous token Console.WriteLine("Failed to establish a connection to '{0}' because the CancelKeyPress event fired first. Exiting...", uri);
closedTokenSource?.Dispose(); return 0;
}
// Create a new token for this run
closedTokenSource = new CancellationTokenSource();
// Connect to the server
} while (!await ConnectAsync(connection));
Console.WriteLine("Connected to {0}", uri); Console.WriteLine("Connected to {0}", uri);
// Handle the connected connection // Handle the connected connection
while (true) while (true)
{ {
try // If the underlying connection closes while waiting for user input, the user will not observe
{ // the connection close aside from "Connection closed..." being printed to the console. That's
// because cancelling Console.ReadLine() is a royal pain.
var line = Console.ReadLine(); var line = Console.ReadLine();
if (line == null || closedTokenSource.Token.IsCancellationRequested) if (line == null || closedTokenSource.Token.IsCancellationRequested)
{ {
Console.WriteLine("Exiting...");
break; break;
} }
try
{
await connection.InvokeAsync<object>("Send", line); await connection.InvokeAsync<object>("Send", line);
} }
catch (ObjectDisposedException) catch when (closedTokenSource.IsCancellationRequested)
{ {
// We're shutting down the client // We're shutting down the client
Console.WriteLine("Failed to send '{0}' because the CancelKeyPress event fired first. Exiting...", line);
break; break;
} }
catch (Exception ex) catch (Exception ex)
@ -114,26 +114,30 @@ namespace ClientSample
Console.WriteLine(ex); Console.WriteLine(ex);
} }
} }
}
finally
{
await connection.StopAsync();
}
return 0; return 0;
} }
private static async Task<bool> ConnectAsync(HubConnection connection) private static async Task<bool> ConnectAsync(HubConnection connection, CancellationToken token)
{ {
// Keep trying to until we can start // Keep trying to until we can start
while (true) while (true)
{ {
try try
{ {
await connection.StartAsync(); await connection.StartAsync(token);
return true; return true;
} }
catch (ObjectDisposedException) catch when (token.IsCancellationRequested)
{ {
// Client side killed the connection
return false; return false;
} }
catch (Exception) catch
{ {
Console.WriteLine("Failed to connect, trying again in 5000(ms)"); Console.WriteLine("Failed to connect, trying again in 5000(ms)");