3

I created a simple ASP.NET websocket server from the sample app at https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/fundamentals/websockets/samples/2.x/WebSocketsSample

Works great from the provided Razor page...

enter image description here Here is part of the server code that accepts the socket connection.

        app.Use(async (context, next) =>
        {
            if (context.Request.Path == "/ws")
            {
                if (context.WebSockets.IsWebSocketRequest)
                {
                    WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
                    await Echo(context, webSocket);
                }
                else
                {
                    context.Response.StatusCode = 400;
                }
            }
            else
            {
                await next();
            }

        });

But now using code adapted from https://www.websocket.org/echo.html it fails badly...

enter image description here

Here is the part of the adapted code...

//  var wsUri = "wss://echo.websocket.org/";
var wsUri = "ws://localhost:36472/ws"
var output;

function init()
{
   output = document.getElementById("output");
   testWebSocket();
}

function testWebSocket()
{
   websocket = new WebSocket(wsUri);
   websocket.onopen = function(evt) { onOpen(evt) };
   websocket.onclose = function(evt) { onClose(evt) };
   websocket.onmessage = function(evt) { onMessage(evt) };
   websocket.onerror = function(evt) { onError(evt) };
}

Is this the expected behavior?! Is there no way for javascript and ASP.NET Core to interoperate through websockets?!

AQuirky
  • 4,691
  • 2
  • 32
  • 51

1 Answers1

2

I tried to replicate your issue, but it seems to be working fine.

I started a new .NET Core project and I added a code from WebSocketsSample you've mentioned:

Startup.cs

using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace WebApplication3
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            var webSocketOptions = new WebSocketOptions()
            {
                KeepAliveInterval = TimeSpan.FromSeconds(120),
                ReceiveBufferSize = 4 * 1024
            };

            app.UseWebSockets(webSocketOptions);

            app.Use(async (context, next) =>
            {
                if (context.Request.Path == "/ws")
                {
                    if (context.WebSockets.IsWebSocketRequest)
                    {
                        WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
                        await Echo(context, webSocket);
                    }
                    else
                    {
                        context.Response.StatusCode = 400;
                    }
                }
                else
                {
                    await next();
                }

            });

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseStaticFiles();
            app.UseMvc();
        }

        private async Task Echo(HttpContext context, WebSocket webSocket)
        {
            var buffer = new byte[1024 * 4];
            WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            while (!result.CloseStatus.HasValue)
            {
                await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);

                result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            }
            await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
        }
    }
}

Program.cs

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace WebApplication3
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

On the UI side I created an empty page and pasted a JS code your provided:

Index.cshtml

@page
@model IndexModel
@{
    ViewData["Title"] = "";
}

<div id="output"></div>

@section Scripts{
    <script language="javascript" type="text/javascript">

    //var wsUri = "wss://echo.websocket.org/";
    var wsUri = "wss://localhost:44357/ws";
    var output;

    function init() {
        output = document.getElementById("output");
        testWebSocket();
    }

    function testWebSocket() {
        websocket = new WebSocket(wsUri);
        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("CONNECTED");
        doSend("WebSocket rocks");
    }

    function onClose(evt) {
        writeToScreen("DISCONNECTED");
    }

    function onMessage(evt) {
        writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data + '</span>');
        websocket.close();
    }

    function onError(evt) {
        writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
    }

    function doSend(message) {
        writeToScreen("SENT: " + message);
        websocket.send(message);
    }

    function writeToScreen(message) {
        var pre = document.createElement("p");
        pre.style.wordWrap = "break-word";
        pre.innerHTML = message;
        output.appendChild(pre);
    }

    window.addEventListener("load", init, false);

    </script>
}

_Layout.cshtml

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>WebApplication</title>
</head>
<body>
    <div>
        @RenderBody()
    </div>
    @RenderSection("Scripts", required: false)
</body>
</html>

And here is a result I'm getting:

enter image description here

Just in case here is a zip archive with code: https://ufile.io/pm2ljcbn

So your code should be fine. Am I missing anything?

Pavel Kovalev
  • 7,521
  • 5
  • 45
  • 67
  • 1
    It seems to me by inspection that your Razor page is connecting to wss://echo.websocket.org/ which of course is going to work. In my code I have a completely independent webpage which is connecting to the local ASP.NET Core server (in my case ws://localhost:36472/ws. – AQuirky May 08 '19 at 17:59
  • @AQuirky my bad, old copy! Please change it to `var wsUri = "wss://localhost:44357/ws";` it works just fine. I updated my answer as well. – Pavel Kovalev May 08 '19 at 18:14
  • Indeed. Here is the interesting thing. My code now works as well. Neither Chrome nor Edge connection worked last night. Today the chrome connection works but still not Edge. So this is not a web socket issue...it seems to be a browser security issue. Perhaps CORS? Still need to figure this out but it is simply a different question now. Thanks for your help. – AQuirky May 08 '19 at 18:24
  • Indeed my problem is exactly the one described here: https://stackoverflow.com/questions/31772564/websocket-to-localhost-not-working-on-microsoft-edge – AQuirky May 08 '19 at 18:36