首页 > 解决方案 > 如何在 C# .NET Core 3.1 中使用 Web 套接字?

问题描述

我正在尝试在我的 Web 应用程序中实现实时通知。只有我的网络应用程序中的管理员用户才能看到通知。
所以我在我的 startup.cs 文件中设置了网络套接字which I think is not the right way

启动.cs

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();
                        
             }
             else
             {
                 context.Response.StatusCode = 400;
             }
         }
         else
         {
            await next();
         }
   });

这是我的 Javascript

window.onload = () => {
    if (/*User is Admin*/) {

        //Establish Websocket
        var socket = new WebSocket("wss:localhost:44301/ws");

        console.log(socket.readyState);

        socket.onerror = function (error) {
            console.log('WebSocket Error: ' + error);
        };

        socket.onopen = function (event) {          
            console.log("Socket connection opened")
        };

        // Handle messages sent by the server.
        socket.onmessage = function (event) {
            var data = event.data;
            console.log(data);
            //Draw some beautiful HTML notification
        };
    }
}

现在这一切正常,但我不知道如何从我的服务器控制器发送消息,像这样

[HttpGet]
public async Task<IActionResult> Foo(WebSocket webSocket)
{
    //What I am trying to do is send message from the open web socket connection.
    var buffer = new byte[1024 * 4];
    buffer = Encoding.UTF8.GetBytes("Foo");

    await webSocket.SendAsync(new ArraySegment<byte>(buffer),WebSocketMessageType.Text,true,CancellationToken.None);
    return View()
}

我不知道如何处理这个问题。我想做的是,如果用户是管理员,打开 Web 套接字并从其他用户操作发送一些数据,(这意味着从我的一些控制器打开的 Web 套接字写入消息)

标签: c#asp.net-core.net-corewebsocket

解决方案


为了能够从控制器发送到连接的 Web 套接字,您必须能够访问这些连接,作为保存这些连接的对象。

这个答案显示了如何使用单独的类处理单个连接并保持连接处于活动状态(等待 client.RunAsync();)。

完成此操作后,在您的情况下,您可能会创建另一个类 ConnectionContainer。它可能只有一个 ConcurrentDictionary 来保存所有传入连接。然后你必须让这个类对控制器可用。它可以通过依赖注入来完成。在 Startup.cs 中:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(new ConnectionContainer());
    ...

}

并在控制器的 ctor 中添加 ConnectionContainer 作为参数并将其保存为私有字段:

 public class BroadcastController
 {
     private readonly ConnectionContainer _connectionContainer;

     public BroadcastController(ConnectionContainer connectionContainer)
     {
         _connectionContainer = connectionContainer;
     }
 }

您的 Foo 方法可以直接使用连接,或者您可以在 ConnectionContainer 中实现广播方法(您可以重用它,并且它会被很好地封装)。

顺便说一句,如果您想将 websockets 用于带有 asp.net 核心的 json/文本消息,我同意其他答案——signalR 将更容易使用(更少的代码)。如果您想完全控制 websocket 并根据您的需要对其进行完全优化,您的代码会更好,因为您可以将二进制数据直接传输到 web 客户端(signalR 不支持)。二进制数据可以在带有DataView的客户端中使用。


推荐阅读