【问题标题】:ASP.NET Core with WebSockets - WebSocket handshake never occurs带有 WebSockets 的 ASP.NET Core - WebSocket 握手永远不会发生
【发布时间】:2017-10-27 00:58:29
【问题描述】:

我对 C# 编程非常陌生,以前只使用过 Java。我正在构建的这个项目应该非常简单——我们有一个包含一系列外币对的网页。选择的元素被发送到服务器,服务器以硬编码的汇率值进行响应。要求是这两个操作都是通过使用 WebSocket 来实现的。这是我页面上的JS代码:

var protocol;
var wsUri;
var socket;

window.onload = function(e) {
    e.preventDefault();



    protocol = location.protocol === "https:" ? "wss:" : "ws:";
    wsUri = protocol + "//" + window.location.host;
    socket = new WebSocket(wsUri);

    socket.onopen = e => {
        console.log("socket opened", e);
    };

    document.getElementById("currencypair").onchange = function()
    {
        var selector = document.getElementById("currencypair");
        var text = selector.options[selector.selectedIndex].text;
        socket.send(text);
    };

    socket.onmessage = function (evt) {
        var receivedMessage = evt.data;
        document.getElementById("output").html(receivedMessage);
    };


};

这里是Startup.cs类Configure方法的sn-p:

        app.UseWebSockets();
        app.UseMiddleware<WebSocketMiddleware>();

这是处理请求的中间件类。

public class WebSocketMiddleware
{

    private readonly RequestDelegate _next;

    public WebSocketMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        if (!context.WebSockets.IsWebSocketRequest)
        {
            await _next.Invoke(context);
            return;
        }

        var ct = context.RequestAborted;
        using (var socket = await context.WebSockets.AcceptWebSocketAsync())
        {
            while (true)
            {
                var stringReceived = await ReceiveStringAsync(socket, ct);

                if (CurrencyPairCollection.CurrencyPairs.TryGetValue(stringReceived, out var value))
                {
                    await SendStringAsync(socket, value.ToString(), ct);
                }
                else
                {
                    throw new Exception("Unexpected value");
                }
                await Task.Delay(1000, ct);
            }
        }

    }

    private static async Task<string> ReceiveStringAsync(WebSocket socket, CancellationToken ct = default(CancellationToken))
    {
        var buffer = new ArraySegment<byte>();
        using (var ms = new MemoryStream())
        {
            WebSocketReceiveResult result;
            do
            {
                ct.ThrowIfCancellationRequested();

                result = await socket.ReceiveAsync(buffer, ct);
                ms.Write(buffer.Array, buffer.Offset, result.Count);
            }
            while (!result.EndOfMessage);

            ms.Seek(0, SeekOrigin.Begin);
            if (result.MessageType != WebSocketMessageType.Text || result.Count.Equals(0))
            {
                throw new Exception("Unexpected message");
            }

            using (var reader = new StreamReader(ms, Encoding.UTF8))
            {
                return await reader.ReadToEndAsync();
            }
        }
    }

    private static Task SendStringAsync(WebSocket socket, string data, CancellationToken ct = default(CancellationToken))
    {
        var segment = new ArraySegment<byte>(Encoding.UTF8.GetBytes(data));
        return socket.SendAsync(segment, WebSocketMessageType.Text, true, ct);
    }

}

请注意,我正在使用以下示例,其中包含评论部分中人们列出的错误。我尽力解决了这些问题,但是由于我的经验有限,这可能是问题所在。

https://www.softfluent.com/blog/dev/Using-Web-Sockets-with-ASP-NET-Core

基本上,在运行应用程序时,浏览器控制台会立即报告: WebSocket 连接到“ws://localhost:51017/”失败:WebSocket 握手期间出错:意外响应代码:200

【问题讨论】:

  • 这本身不是一个答案,但也许你应该考虑使用 SignalR,它会让你的生活变得轻松 ;-) 但是我看到你正在使用 .Net Core 并且 SignalR 仅适用于 .NET Core 2.1 所以你必须使用每晚构建直到年底(2.1-preview1)
  • 是的,我可能会尝试一下。问题是,要求是 WebSockets。不过还是谢谢。
  • 我不明白。 SignalR 正在使用网络套接字。
  • .NET Core 2.0 也是必须的:) 这是一个面试后收到的项目。
  • 有人有什么建议吗?我今天需要交这个...

标签: c# asp.net websocket


【解决方案1】:

我已经能够回答我自己的问题了。所以在我只提供了一个 sn-p 的 Startup.cs 中,对 app.UseMvc() 的调用是在我已经共享的行之前进行的。这是由默认模板生成的。诀窍是将此调用移至以下内容:

    app.UseWebSockets();
    app.UseMiddleware<WebSocketMiddleware>();

否则请求管道会中断。

这将允许我们的套接字打开,但是不会更改 async Task ReceiveStringAsync(...) 中的以下行

var buffer = new ArraySegment<byte>();

var buffer = new ArraySegment<byte>(new byte[8192]);

它仍然会过早关闭。接下来,只需要纠正 JS 语法错误。改变了

document.getElementById("output").html(receivedMessage);

document.getElementById("output").value = receivedMessage;

就是这样,它起作用了。

【讨论】:

    猜你喜欢
    • 2012-03-22
    • 2015-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-01
    • 2013-05-08
    • 2017-04-15
    • 1970-01-01
    相关资源
    最近更新 更多