Improve shutdown of SignalR .NET client sample (#10675)
This commit is contained in:
parent
c518cff370
commit
511761627a
|
|
@ -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,88 +53,91 @@ namespace ClientSample
|
||||||
|
|
||||||
connectionBuilder.WithAutomaticReconnect();
|
connectionBuilder.WithAutomaticReconnect();
|
||||||
|
|
||||||
|
using var closedTokenSource = new CancellationTokenSource();
|
||||||
var connection = connectionBuilder.Build();
|
var connection = connectionBuilder.Build();
|
||||||
|
|
||||||
Console.CancelKeyPress += (sender, a) =>
|
try
|
||||||
{
|
{
|
||||||
a.Cancel = true;
|
Console.CancelKeyPress += (sender, a) =>
|
||||||
connection.DisposeAsync().GetAwaiter().GetResult();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set up handler
|
|
||||||
connection.On<string>("Send", Console.WriteLine);
|
|
||||||
|
|
||||||
CancellationTokenSource closedTokenSource = null;
|
|
||||||
|
|
||||||
connection.Closed += e =>
|
|
||||||
{
|
|
||||||
// This should never be null by the time this fires
|
|
||||||
closedTokenSource.Cancel();
|
|
||||||
|
|
||||||
Console.WriteLine("Connection closed...");
|
|
||||||
return Task.CompletedTask;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// Dispose the previous token
|
|
||||||
closedTokenSource?.Dispose();
|
|
||||||
|
|
||||||
// Create a new token for this run
|
|
||||||
closedTokenSource = new CancellationTokenSource();
|
|
||||||
|
|
||||||
// Connect to the server
|
|
||||||
} while (!await ConnectAsync(connection));
|
|
||||||
|
|
||||||
Console.WriteLine("Connected to {0}", uri);
|
|
||||||
|
|
||||||
// Handle the connected connection
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
|
a.Cancel = true;
|
||||||
|
closedTokenSource.Cancel();
|
||||||
|
connection.StopAsync().GetAwaiter().GetResult();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up handler
|
||||||
|
connection.On<string>("Send", Console.WriteLine);
|
||||||
|
|
||||||
|
connection.Closed += e =>
|
||||||
|
{
|
||||||
|
Console.WriteLine("Connection closed...");
|
||||||
|
closedTokenSource.Cancel();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!await ConnectAsync(connection, closedTokenSource.Token))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Failed to establish a connection to '{0}' because the CancelKeyPress event fired first. Exiting...", uri);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Connected to {0}", uri);
|
||||||
|
|
||||||
|
// Handle the connected connection
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
await connection.InvokeAsync<object>("Send", line);
|
try
|
||||||
}
|
{
|
||||||
catch (ObjectDisposedException)
|
await connection.InvokeAsync<object>("Send", line);
|
||||||
{
|
}
|
||||||
// We're shutting down the client
|
catch when (closedTokenSource.IsCancellationRequested)
|
||||||
break;
|
{
|
||||||
}
|
// We're shutting down the client
|
||||||
catch (Exception ex)
|
Console.WriteLine("Failed to send '{0}' because the CancelKeyPress event fired first. Exiting...", line);
|
||||||
{
|
break;
|
||||||
// Send could have failed because the connection closed
|
}
|
||||||
// Continue to loop because we should be reconnecting.
|
catch (Exception ex)
|
||||||
Console.WriteLine(ex);
|
{
|
||||||
|
// Send could have failed because the connection closed
|
||||||
|
// Continue to loop because we should be reconnecting.
|
||||||
|
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)");
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue