Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

System.ObjectDisposedException throwed on WebSocket communication

I'm trying to communicate between a web browser client and an ASP.NET server using WebSockets.

I make a set of requests, of different sizes and with some seconds of elapsed time between each of them. The three first ones pass correctly, but a precise one, with nothing in particular from the other, close the WebSocket connection, throw an exception on server side.

The error message and stack trace of this exception look like this :

FATAL ERROR: Cannot access a disposed object.
Object name: 'System.Web.WebSockets.AspNetWebSocket'.
at System.Web.WebSockets.AspNetWebSocket.ThrowIfDisposed()
at System.Web.WebSockets.AspNetWebSocket.SendAsyncImpl(ArraySegment 1 buffer, WebSocketMessageType messageType, Boolean endOfMessage, CancellationToken cancellationToken, Boolean performValidation)
at System.Web.WebSockets.AspNetWebSocket.SendAsync(ArraySegment 1 buffer, WebSocketMessageType messageType, Boolean endOfMessage, CancellationToken cancellationToken)
at [my code path here...]

It may be a threading problem, because I'm using async methods everywhere from functions that communicate with websockets.

I know the exception is throwed from this code (at socket.SendAsync):

public class SocketTranslater
{

    private WebSocket socket;
    private JavaScriptSerializer serializer;

    // [...]

    private ArraySegment<byte> Encode(Object data)
    {
        string json = serializer.Serialize(data);
        return (new ArraySegment<byte>(Encoding.UTF8.GetBytes(json)));
    }


    public async Task Send(Object packet)
    {
        ArraySegment<byte> encoded = this.Encode(packet);

        await socket.SendAsync(encoded, WebSocketMessageType.Text, true, CancellationToken.None);
    }
}

The socket is created from another class :

public class EventSender : IHttpHandler
{
    private static List<SocketTranslater> socketTranslaters = new List<SocketTranslater>();

    public void ProcessRequest(HttpContext context)
    {
        this.id = context.Request.UserHostName + ":" + context.Request.UserAgent;
        if (context.IsWebSocketRequest)
        {
            context.AcceptWebSocketRequest(ProcessSocket);
        }        
    }

    private async Task ManageSocket(AspNetWebSocketContext context)
    {
        WebSocket socket = context.WebSocket;
        SocketTranslater translater = new SocketTranslater(socket);
        translaters.add(translater);

        while (true)
        {
            // Manage messages, using the other class to send responses.
            translater.Send(/* Any struct here */);
        }
    }

Unhopefully, my project is too big to put all the code here.

Any idea of error source, or additional information that you would require ?

UPDATE:

After some more tests, I don't have this exception from time to time. I always do the same thing, but the server seems to have a random comportment.

That makes my problem even weirder...

like image 405
Aracthor Avatar asked Nov 09 '22 14:11

Aracthor


1 Answers

Finally, after some more tests and interesting questions and answer from here (like this one), I understood:

My problem was that I was stocking WebSockets in a Dictionary linked with hostnames. So on the first connection of a client on my server, everything worked correctly. But if I refresh the page, the websocket was closed by the server (because there was no chance to use it again) et another one was created.

But as I used the same key for both sockets, the deprecated and the new one, I was trying to answer to the new client with the previous socket, that was closed. (disposed = closed for ASP.NET).

So the only thing that I had to do is to remove a socket from the list on the client disconnection (at the end of ManageSocket). And forbid a client to connect twice with the same hostname.

I didn't mention the part where I was linking sockets with hostnames, so I admit you couldn't really help me... I apologize.

like image 78
Aracthor Avatar answered Nov 14 '22 21:11

Aracthor