File: HubSample.cs
Web Access
Project: src\src\SignalR\samples\ClientSample\ClientSample.csproj (ClientSample)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
 
namespace ClientSample;
 
internal class HubSample
{
    internal static void Register(CommandLineApplication app)
    {
        app.Command("hub", cmd =>
        {
            cmd.Description = "Tests a connection to a hub";
 
            var baseUrlArgument = cmd.Argument("<BASEURL>", "The URL to the Chat Hub to test");
 
            cmd.OnExecute(() => ExecuteAsync(baseUrlArgument.Value));
        });
    }
 
    public static async Task<int> ExecuteAsync(string baseUrl)
    {
        var uri = baseUrl == null ? new Uri("net.tcp://127.0.0.1:9001") : new Uri(baseUrl);
 
        Console.WriteLine("Connecting to {0}", uri);
 
        var connectionBuilder = new HubConnectionBuilder()
            .ConfigureLogging(logging =>
            {
                logging.AddConsole();
            });
 
        connectionBuilder.Services.Configure<LoggerFilterOptions>(options =>
        {
            options.MinLevel = LogLevel.Trace;
        });
 
        if (uri.Scheme == "net.tcp")
        {
            connectionBuilder.WithEndPoint(uri);
        }
        else
        {
            connectionBuilder.WithUrl(uri);
        }
 
        connectionBuilder.WithAutomaticReconnect();
 
        using var closedTokenSource = new CancellationTokenSource();
        var connection = connectionBuilder.Build();
 
        try
        {
            Console.CancelKeyPress += (sender, a) =>
            {
                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();
 
                if (line == null || closedTokenSource.Token.IsCancellationRequested)
                {
                    Console.WriteLine("Exiting...");
                    break;
                }
 
                try
                {
                    await connection.InvokeAsync<object>("Send", "C#", line);
                }
                catch when (closedTokenSource.IsCancellationRequested)
                {
                    // We're shutting down the client
                    Console.WriteLine("Failed to send '{0}' because the CancelKeyPress event fired first. Exiting...", line);
                    break;
                }
                catch (Exception 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;
    }
 
    private static async Task<bool> ConnectAsync(HubConnection connection, CancellationToken token)
    {
        // Keep trying to until we can start
        while (true)
        {
            try
            {
                await connection.StartAsync(token);
                return true;
            }
            catch when (token.IsCancellationRequested)
            {
                return false;
            }
            catch
            {
                Console.WriteLine("Failed to connect, trying again in 5000(ms)");
 
                await Task.Delay(5000);
            }
        }
    }
}