percentum
percentum

Reputation: 153

Azure Web PubSub ClientWebSocket "The server returned status code '401' when status code '101' was expected."

I am trying to use the Web PubSub Service resource in Azure, and have created a basic client using ClientWebSocket. Everything is fine, it sits there waiting for something to come through, however, after 36 hours or so (take that time with a pinch of salt but its a fairly long time), it loses connection, and then when i try and connect again, i get the following error over and over again:

"The server returned status code '401' when status code '101' was expected."

This is sitting inside a Blazor app, and an instance of the client is sitting inside a singleton service that is always running. If i restart the blazor app, then it connects fine again. This is the client i have created:

public class AzurePubSubWebsocketClient
{
    private readonly Uri _serverUri;
    private CancellationTokenSource _cancellationTokenSource;
    private bool _isRunning = false;
    private object _runningLockObject = new object();

    int reconnectDelaySeconds = 5; // Adjust the delay (in seconds) between reconnection attempts.

    public event Action<string> OnLogMessage;
    public event Action<string> OnMessageReceived;

    public AzurePubSubWebsocketClient(Uri serverUri)
    {
        this._serverUri = serverUri;
    }

    public async Task ConnectAndReceiveMessages()
    {
        while (true)
        {
            try
            {
                OnLogMessage?.Invoke("Connecting to WebSocket...");

                using (var clientWebSocket = new ClientWebSocket())
                {
                    await clientWebSocket.ConnectAsync(_serverUri, CancellationToken.None);
                    OnLogMessage?.Invoke("Connected to the WebSocket server.");

                    lock (_runningLockObject)
                    {
                        _isRunning = true;
                    }

                    // Receive messages from the server in a loop.
                    byte[] receiveBuffer = new byte[4096];
                    WebSocketReceiveResult receiveResult;

                    while (clientWebSocket.State == WebSocketState.Open)
                    {
                        receiveResult = await clientWebSocket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);

                        if (receiveResult.MessageType == WebSocketMessageType.Text)
                        {
                            string message = Encoding.UTF8.GetString(receiveBuffer, 0, receiveResult.Count);
                            OnLogMessage?.Invoke($"Received message: {message}");

                            try
                            {
                                OnMessageReceived?.Invoke(message);
                            }
                            catch (Exception exception)
                            {
                                OnMessageReceived?.Invoke(exception.Message);
                            }
                        }
                    }

                    lock (_runningLockObject)
                    {
                        _isRunning = false;
                    }
                }
            }
            catch (Exception ex)
            {
                lock (_runningLockObject)
                {
                    _isRunning = false;
                }

                OnLogMessage?.Invoke($"Error: {ex.Message}");
            }              

            // Reconnection delay to avoid frequent connection attempts.
            OnLogMessage?.Invoke($"Connection lost. Retrying in {reconnectDelaySeconds} seconds...");
            await Task.Delay(TimeSpan.FromSeconds(reconnectDelaySeconds));
        }
    }

    public bool IsRunning()
    {
        lock (_runningLockObject)
        {
            return _isRunning;
        }
    }
}

The first time connection is lost, there is no Exception, it just comes out the while loop (though to be fair im not logging what the MessageType is) and then after that everytime it tries to connect i get that 401 error.

[03/08/23 11:18:16.104] Connection lost. Retrying in 5 seconds...

[03/08/23 11:18:21.103] Connecting to WebSocket...

[03/08/23 11:18:21.148] Error: The server returned status code '401' when status code '101' was expected.

[03/08/23 11:18:21.148] Connection lost. Retrying in 5 seconds...

[03/08/23 11:18:26.150] Connecting to WebSocket...

[03/08/23 11:18:26.163] Error: The server returned status code '401' when status code '101' was expected.

[03/08/23 11:18:26.163] Connection lost. Retrying in 5 seconds...

[03/08/23 11:18:31.166] Connecting to WebSocket...

[03/08/23 11:18:31.209] Error: The server returned status code '401' when status code '101' was expected.

[03/08/23 11:18:31.209] Connection lost. Retrying in 5 seconds...

[03/08/23 11:18:36.198] Connecting to WebSocket...

[03/08/23 11:18:36.256] Error: The server returned status code '401' when status code '101' was expected.

[03/08/23 11:18:36.256] Connection lost. Retrying in 5 seconds...

[03/08/23 11:18:41.263] Connecting to WebSocket...

Upvotes: 0

Views: 1152

Answers (1)

Suresh Chikkam
Suresh Chikkam

Reputation: 3297

Error: The server returned status code '401' when status code '101' was expected.

public class AzurePubSubWebsocketClient
{
    private readonly Uri _serverUri;
    private bool _isRunning;
    private readonly object _runningLockObject = new object();

    public event Action<string> OnMessageReceived;
    public event Action<string> OnLogMessage;

    public AzurePubSubWebsocketClient(Uri serverUri)
    {
        _serverUri = serverUri;
    }

    public async Task ConnectAndReceiveMessages()
    {
        // Sample token for testing purposes (replace with your actual token)
        string sampleToken = "YOUR_SAMPLE_TOKEN_HERE";

        while (true)
        {
            try
            {
                OnLogMessage?.Invoke("Connecting to WebSocket...");

                using (var clientWebSocket = new ClientWebSocket())
                {
                    // Add the sample token to the headers
                    clientWebSocket.Options.SetRequestHeader("Authorization", $"Bearer {sampleToken}");

                    await clientWebSocket.ConnectAsync(_serverUri, CancellationToken.None);
                    OnLogMessage?.Invoke("Connected to the WebSocket server.");

                    lock (_runningLockObject)
                    {
                        _isRunning = true;
                    }

                    // Receive messages from the server in a loop.
                    byte[] receiveBuffer = new byte[4096];
                    WebSocketReceiveResult receiveResult;

                    while (clientWebSocket.State == WebSocketState.Open)
                    {
                        receiveResult = await clientWebSocket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);

                        if (receiveResult.MessageType == WebSocketMessageType.Text)
                        {
                            string message = Encoding.UTF8.GetString(receiveBuffer, 0, receiveResult.Count);
                            OnLogMessage?.Invoke($"Received message: {message}");

                            try
                            {
                                OnMessageReceived?.Invoke(message);
                            }
                            catch (Exception exception)
                            {
                                OnLogMessage?.Invoke(exception.Message);
                            }
                        }
                    }

                    lock (_runningLockObject)
                    {
                        _isRunning = false;
                    }
                }
            }
            catch (Exception ex)
            {
                lock (_runningLockObject)
                {
                    _isRunning = false;
                }

                OnLogMessage?.Invoke($"Error: {ex.Message}");
            }

            // Reconnection delay to avoid frequent connection attempts.
            int reconnectDelaySeconds = 5; // Change this as needed
            OnLogMessage?.Invoke($"Connection lost. Retrying in {reconnectDelaySeconds} seconds...");
            await Task.Delay(TimeSpan.FromSeconds(reconnectDelaySeconds));
        }
    }

    public bool IsRunning()
    {
        lock (_runningLockObject)
        {
            return _isRunning;
        }
    }
}
  • In this above code, I've added a sample token (replace with your actual token) directly in the WebSocket headers. This way, you can focus on testing the reconnection behavior and the 401 error issue without worrying about token generation. The rest of the logic remains similar to your own code, but with additional logging to help you monitor the WebSocket connection and any errors that might occur.

If the WebSocket is in another domain, then configure the CORS to allow requests from your client's domain.

enter image description here

Here I can see in monitoring metrics that which get the request from client server:

enter image description here

Upvotes: 0

Related Questions