0
votes

I am very new to websockets and WebAPI (our system has been all .NET MVC, just not WebAPI), so I may very well just be missing something obvious (I hope).

I am attempting to implement a simple client to play around with. I am working in .NET in (sadly) VB, and I'm trying to just get the websocket working, and hitting the OnOpen/Message/Close events server and client side.

My code is below, but in short, the websocket handshake seems to happen without any issue, as my onOpen() event in the javascript gets hit, and when I output the readyState its 1. However OnOpen does NOT get hit server side

The output ends up looking like this:

IMMEDIATE READYSTATE: 0

ONOPEN READYSTATE: 1

Socket closed

The constructor for my WebSocketHandler is hit (for example if I throw a breakpoint on the MyBase.New() line, it hits it). However OnOpen is never hit, and the socket immediately hits the onclose event in the js.. is there something I should be doing to keep the socket open? Why would OnOpen not get hit?

My code is below:

Javascript:

var wsUri = 'ws://' + window.location.hostname + '/api/Chat?username=hello';
var output;

$(document).ready(function () {

  //setup and fire
  output = document.getElementById("output");
  testWebSocket();
})

function testWebSocket() {
  //Instantiate the websocket, hopefully opening it
  websocket = new WebSocket(wsUri);
  writeToScreen("IMMEDIATE READYSTATE: " + websocket.readyState);

  //bind event handlers
  websocket.onopen = function (evt) { onOpen(evt) };
  websocket.onclose = function (evt) { onClose(evt) };
  websocket.onmessage = function (evt) { onMessage(evt) };
  websocket.onerror = function (evt) { onError(evt) };
}

function onOpen(evt) {
  writeToScreen("ONOPEN READYSTATE: " + websocket.readyState);
  websocket.send("Websocket's open!")
}

function onClose(evt) {
  writeToScreen("Socket closed");
}

function onMessage(evt) {
  writeToScreen('RECEIVED: ' + evt.data);
}

function onError(evt) {
  writeToScreen('ERROR:' + evt.data);
}


function writeToScreen(message) {
  var messageToAppend = document.createElement("p");
  messageToAppend.style.wordWrap = "break-word";
  messageToAppend.innerHTML = '<span>' + message + '</span>';
  output.appendChild(messageToAppend);
}

Server:

Public Class ChatController
  Inherits ApiController

  Public Function [Get](username As String) As HttpResponseMessage

    If HttpContext.Current.IsWebSocketRequest Then
      HttpContext.Current.AcceptWebSocketRequest(Function() Tasks.Task.FromResult(New ChatWebSocketHandler(username)))
      Return Request.CreateResponse(HttpStatusCode.SwitchingProtocols)
    Else
      Return Request.CreateResponse(HttpStatusCode.BadRequest)
    End If
  End Function


  Private Class ChatWebSocketHandler
    Inherits Microsoft.Web.WebSockets.WebSocketHandler

    Public Sub New(username As String)

      MyBase.New()

      'Do stuff with username eventually.

    End Sub

    Public Overrides Sub OnOpen()
      Debug.WriteLine("Websocket is open")
    End Sub

    Public Overrides Sub OnMessage(message As String)
      Debug.WriteLine("Message Received: " & message)
    End Sub

    Public Overrides Sub OnClose()

      Debug.WriteLine("Websocket Closed")

      MyBase.OnClose()

    End Sub
  End Class

End Class
1
Quick note: after posting this I added an override to OnError in my server code to see if it's hitting that by chance, but to no avail - CTDev
javascript appears to be working just fine. Should be your server code's fault (note: i did not test with jquery, i just used window.addEventListener("load", testWebSocket, false); and connected to ws://echo.websocket.org, which is useful as a test server here) - ASDFGerte
Any idea what is wrong with my server? The HTTP Request seems to be making it,, is recognizing it as a WebSocketRequest and then accepting it without error, and in addition my WebSocketHandler's constructor is also hit, again with no errors. But then it's like it just dies immediately (or maybe never even fully instantiates since OnOpen() is never hit server side?). - CTDev
I have never used VB before, so i cannot make an educated comment on that. I always used open-source websocket server libraries with e.g. an MIT license, so i also did not delve into the websocket protocol specifics too much either. - ASDFGerte

1 Answers

0
votes

To be honest, I cant say with 100% certainty what fixed this, but I have a very strong suspicion.

I was including too many namespaces in my code and I believe there was some confusion in the compiler etc when it actually ran. Apparently both Microsoft.Web.Websockets and SignalR's namespaces BOTH contain WebSocketHandler. While I dont know all the ins and outs of SignalR, it looks like WebSocketHandler in THAT namespace is not meant to be used outside of SignalR. I believe that class was being referenced instead of the one in Microsoft.Web.Websockets, as it works now, but I really didn't change too much. It also let me directly call the constructor by instantiating a new instance of the handler instead of having to call it in a lambda function.

Anyway, If anyone else has similar issues, make sure you're referencing the right one!