ergen
ergen

Reputation: 95

prevent application crashes when sending data over a closed websocket connection

The ASP.NET Core application uses websocket connection on the client side and Microsoft.AspNetCore.WebSockets.Server 0.1.0 (latest stable version on nuget as I know) on the server side. The simple sending code is

await _ws.SendAsync(new ArraySegment<byte>(arrbr), WebSocketMessageType.Text, true, ctk); 

the problem is this line throws error when it is a closed connection. I would like that method to return a Boolean if process was successful. I already check if the connection is open like this:

_ws.State == WebSocketState.Open 

But this does not work if user has unplugged the network cable or disconnected his device(almost all situations except closing the browsers).

As an extra, I do not know how to simulate network connection loss for one of two clients and I suppose WebSocketState is readonly, please warn me if I am wrong and I do not think shorter pings will solve this problem.
I have two ideas:

  1. I may use the sender code in a try catch block. (I am not comfortable with using try catch in production code)

  2. I may set interval on the client side, and ask the server like "what is new for me". I feel bad with this because it is away from being a websocket(closer to http).

Is there any way to fix this without using try catch? I know that this is not a qualified question but a qualified problem for me. I can share full code if needed.

Update 1

after using server-side logging:
While messaging is working well in production environment, I disconnect the client by unplugging the network cable and send data to the client. I use try catch and no catch. then i get this error.
This means I cant detect lost connection by using try catch. and i think i can solve this by handling this throw.
How can I handle this error?

update2

I have noticed that "Exceptions from an Async Void Method Can’t Be Caught with Catch" and "it's possible to use await in catch" since c# 6 link however I can not catch the throw.
I may try running synchronously await _ws.SendAsync(new ArraySegment<byte>(arrbr), WebSocketMessageType.Text, true, ctk).runsynchronously(); if I cant fix in this way

update3

running synchronously does not help. using try catch does not differ. as a result question, asp.net core websocket how to ping

update4

my log file when using Microsoft.aspnetcore.websockets.server 0.1.0

fail: Microsoft.AspNetCore.Server.Kestrel[13] Connection id "0HL1940BSEV8O": An unhandled exception was thrown by the application. System.IO.IOException: Unexpected end of stream at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<EnsureDataAvailableOrReadAsync>d__38.MoveNext()
my log file when using Microsoft.aspnetcore.websockets 1.0.0 fail: Microsoft.AspNetCore.Server.Kestrel[13] Connection id "0HL19H5R4CS21": An unhandled exception was thrown by the application. System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.IO.IOException: Error -4077 ECONNRESET connection reset by peer ---> Microsoft.AspNetCore.Server.Kestrel.Internal.Networking.UvException: Error -4077 ECONNRESET connection reset by peer

Upvotes: 1

Views: 4309

Answers (2)

Viktor Balykhin
Viktor Balykhin

Reputation: 96

Until C# 6.0 to capture an exceptions from async methods you should use the ExceptionDispatchInfo type. Then the code will look like this:

private async Task<bool> DoSend()
{
    bool success = true;
    ExceptionDispatchInfo capturedException = null;

    try
    {
        await _ws.SendAsync(new ArraySegment<byte>(arrbr), WebSocketMessageType.Text, true, ctk);
    }
    catch (Exception ex)
    {
        capturedException = ExceptionDispatchInfo.Capture(ex);
    }

    if (capturedException != null)
    {
        await ExceptionHandler();

        if (needsThrow)
        {
            capturedException.Throw();
        }
    }

    success = capturedException == null;

    return success;
}

Upvotes: 0

Itay Podhajcer
Itay Podhajcer

Reputation: 2656

I might be missing something, but why can't wrap the sending operation in a method that returns bool in the following manner:

private async Task<bool> DoSend()
{
    bool success = true;

    try
    {
        await _ws.SendAsync(new ArraySegment<byte>(arrbr), WebSocketMessageType.Text, true, ctk);
    }
    catch (Exception ex)
    {
        // Do some logging with ex
        success = false;
    }

    return success;
}

I also suggest reading about Async All The Way, it should clear some of the confusion with async void, async Task and async Task<T>

Upvotes: 7

Related Questions