I'm trying to create an application that uses websockets for various purposes.
At the time, I started developing a chat that is the most common example and I require it for a small inter-institutional help chat, among other things that I plan to implement with this technology.
The problem arises when when creating the websocket, it does not stay open. The onopen () method works without problem but somehow the page is recharged and tries to create a new socket so then the onclose method of the previous socket is called and it closes it, then I'm left without any open.
This is the class that manages the request and handles messages:
public class WebSocketController : ApiController
{
private WebSocketHandler socketHandler { get; set; }
// GET: WebSocket
public HttpResponseMessage Get()
{
if(HttpContext.Current.IsWebSocketRequest)
{
HttpContext.Current.AcceptWebSocketRequest(ProcessWS);
}
return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
}
private async Task ProcessWS(AspNetWebSocketContext context)
{
var socket = context.WebSocket;
//var buffer = new byte[1024 * 4];
await socketHandler.OnConnected(socket);
await Receive(socket);
}
private async Task Receive(WebSocket socket)
{
var buffer = new byte[1024 * 4];
while(socket.State == WebSocketState.Open)
{
var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
await ManejaMensaje(socket, result, buffer);
}
}
private async Task ManejaMensaje(WebSocket socket, WebSocketReceiveResult result, byte[] buffer)
{
if(result.MessageType == WebSocketMessageType.Text)
{
await socketHandler.ReceiveAsync(socket, result, buffer);
return;
}
else if(result.MessageType == WebSocketMessageType.Close)
{
await socketHandler.OnDisconnected(socket);
return;
}
}
}
The main page is nothing more than a text field where a user is entered:
<h2>Inicia sesion...</h2>
<form action="@Url.Action("Index")" method="post">
<input type="text" placeholder="Inserta el nombre de usuario" name="usuario" /> <br />
<input type="submit" value="Enter" />
</form>
And in the chat window you have an area to show the messages and a field to write. In addition to the scripts for websockets:
@model string
@{
ViewBag.Title = "ChatRoom";
}
<style>
.areamsg {
position: absolute;
top: 200px;
bottom: 30px;
border: 1px solid gray;
margin-bottom: auto;
display: block;
overflow: scroll;
width: 50%;
white-space: nowrap;
}
</style>
<script src="~/Scripts/jquery-3.2.1.js"></script>
<h2>Bienvenido <b>@ViewBag.Usuario</b></h2>
<span id="spanStatus">(display)</span>
<div id="areamsg" class="areamsg">
<div id="msgs" style="position:absolute; bottom:0;"></div>
</div>
<div id="inputArea" style="position:absolute;height:20px;bottom:10px;left:390px; display:block;width:100%">
<input id="MessageField" type="text" style="max-width:unset;width:50%;max-width:50%" placeholder="Escribe tu mensaje y presiona enter" />
</div>
<script>
$(function () {
$("#spanStatus").text("Conectando...");
var user = '@ViewBag.Usuario';
var protocolo = location.protocol === "https:" ? "wss:" : "ws:";
var api = "/api/WebSocket";
var wsUri = protocolo + "//" + window.location.host + api;
var socket = new WebSocket(wsUri);
socket.onopen = function (e) {
$("#spanStatus").text("Conectado!");
console.log(e);
};
socket.onclose = function (e) {
$("#spanStatus").text("Desconectado");
console.log(e);
};
socket.onmessage = function (e) {
$("#areamsg").append(e.data + '<br />');
console.log(e);
};
socket.onerror = function (e) {
console.log(e.data);
};
$("#MessageField").keypress(function (e) {
if (e.which != 13)
{
return;
}
e.preventDefault();
var mensaje = user + ": " + $("#MessageField").val();
socket.send(mensaje);
$("#MessageField").val('');
});
});
</script>
This is what the Firefox console shows:
open { target: WebSocket, isTrusted: true, eventPhase: 0, bubbles: false, cancelable: false, defaultPrevented: false, composed: false, timeStamp: 699.7398017332215, cancelBubble: false, originalTarget: WebSocket, explicitOriginalTarget: WebSocket } localhost:51043:43:13
La conexión a ws://localhost:51043/api/WebSocket fue interrumpida mientras la página se cargaba. localhost:51043:39:21
error { target: WebSocket, isTrusted: true, eventPhase: 0, bubbles: false, cancelable: false, defaultPrevented: false, composed: false, timeStamp: 16279.039515798435, cancelBubble: false, originalTarget: WebSocket, explicitOriginalTarget: WebSocket }
close { target: WebSocket, isTrusted: true, wasClean: false, code: 1006, reason: "", eventPhase: 0, bubbles: false, cancelable: false, defaultPrevented: false, composed: false, timeStamp: 760.4769653024605 }
The Global.asax is as it was created with the project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using System.Web.SessionState;
using System.Web.Http;
namespace WebSocketsGrid
{
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
// Código que se ejecuta al iniciar la aplicación
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}
}
As you can see, the connection opens but closes immediately. In the part where it says that the connection was interrupted, it's where a "ChatRoom" recharge is apparently made, that is, it is loaded twice or at least I think so.
I can say that I have two examples downloaded from the internet, practically identical to what I want, which I run and open the connection without problems but my application does not work.