CanardMoussant
CanardMoussant

Reputation: 923

Chain 2 websockets in .NET (using asp.net 4.5)

I would like to open a GET method on server side that will simply opens a websocket to another webserver and act as a simple gateway between the client and the other server.

It is quite straightforward to get the websocket between the client and the first webserver, but I cannot find how to easily open another and forward the messages. Note that I do not even need to listen to what the client is pushing for the moment: all messages come from the second webserver.

Upvotes: 0

Views: 1193

Answers (1)

CanardMoussant
CanardMoussant

Reputation: 923

I managed to write the following code which seems to be ok. Since I asked the question here, I post my code. Any comment would be much appreciated.

[Route("api/{slip}")]
[HttpGet]
public async Task<IHttpActionResult> TrackJob(String slip)
{
    var serverEndpoint = string.Format("ws://{0}/api/services", slip);

    HttpContext currentContext = HttpContext.Current;
    if (currentContext.IsWebSocketRequest)
    {
        try
        {
            currentContext.AcceptWebSocketRequest(GetWebSocketSession(serverEndpoint));
            return ResponseMessage(Request.CreateResponse(HttpStatusCode.SwitchingProtocols));
        }

        catch (Exception ex)
        {
            Console.WriteLine(ex);
            throw ex;
        }
    }
    else
    {
        return NotFound();
    }
}

private Func<AspNetWebSocketContext, Task> GetWebSocketSession(String serverEndpoint)
{
    Func<AspNetWebSocketContext, Task> func = async (context) =>
    {
        var wsToClient = context.WebSocket;

        using (var wsToProcessingCluster = new ClientWebSocket())
        { 
            new Task(async () =>
            {
                var inputSegment = new ArraySegment<byte>(new byte[1024]);

                while (true)
                {
                    // MUST read if we want the state to get updated...
                    try
                    {
                        await wsToClient.ReceiveAsync(inputSegment, CancellationToken.None);
                    }

                    catch (Exception ex)
                    {
                        Console.WriteLine(ex);
                        return;
                    }

                    if (wsToClient.State != WebSocketState.Open)
                    {
                        await wsToProcessingCluster.CloseAsync(WebSocketCloseStatus.Empty, "", CancellationToken.None);
                        break;
                    }
                }
            }).Start();

            var buffer = new byte[1024];
            var uri = new Uri(serverEndpoint);
            await wsToProcessingCluster.ConnectAsync(uri, CancellationToken.None);
            while (true)
            {
                if (wsToClient.State != WebSocketState.Open)
                {
                    break;
                }
                else
                {
                    var segment = new ArraySegment<byte>(buffer);
                    var result = await wsToProcessingCluster.ReceiveAsync(segment, CancellationToken.None);

                    await wsToClient.SendAsync(segment, result.MessageType, result.EndOfMessage, CancellationToken.None);
                }
            }
        }
    };

    return func;
}

Upvotes: 1

Related Questions