使用WebSocket更新客户端数据(单向)的示例

时间:2019-05-19 22:51:07

标签: c# asp.net-core websocket

我正在使用ASP.NET Core探索WebSockets,我偶然发现的大多数教程都以相同的方式对此进行了解释:客户端发送请求,服务器在Startup类中获取请求并重新发送相同的数据。我正在寻找一种方法,可以在服务器端更改网页内容后立即对其进行更新。例如,为简单起见,我的页面上的数字每2秒递增一次, 我想更新此值的HTML处理程序:

PageModel:

public class IndexModel : PageModel
{
    private int _myNumber;
    private Timer _timer;

    public int MyNumber
    {
        get => _myNumber;
        set
        {
            if (value != _myNumber)
            {
                _myNumber = value;
                //send data to the client via web socket
            }
        }
    }

    public void OnGet()
    {
        SetTimer();
    }

    private void SetTimer()
    {
        _timer = new Timer(new TimerCallback((state) => ++MyNumber));
        var period = TimeSpan.FromMilliseconds(2000);
        _timer.Change(TimeSpan.Zero, period);
    }
}

Index.cshtml:

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


<h1>Number: </h1>
<h3 id="myNumber" style="background-color: yellow">@Model.MyNumber</h3>


<script>
    var socket;
    var scheme = document.location.protocol === "https:" ? "wss" : "ws";
    var port = document.location.port ? (":" + document.location.port) : "";
    var url = scheme + "://" + document.location.hostname + port + "/ws";
    var myNumber = document.getElementById('myNumber');
    console.log("ws url: " + url);
    window.onload = function () {
        myNumber.innerHTML = "00";

        socket = new WebSocket(url);

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

        socket.onclose = function (event) {
            console.log("closed connection from " + url);
        };

        socket.onerror = function (event) {
            console.log("error: " + event.data);
        };

        socket.onmessage = function (event) {
            console.log("event.data: " + event.data);
            myNumber.innerHTML = event.data;
        }
    };


</script>

在启动类中,我可以达到的最佳结果是

配置方法:

 {...
     app.UseMvc();
     var opts = new WebSocketOptions
     {
         KeepAliveInterval = TimeSpan.FromSeconds(120),
         ReceiveBufferSize = 4 * 1024
     };
     app.UseWebSockets(opts);
     app.Use(async (context, next) =>
     {
         if (context.Request.Path == "/ws")
         {
             if (context.WebSockets.IsWebSocketRequest)
             {
                 _webSocket = await context.WebSockets.AcceptWebSocketAsync();
                 await Echo();
             }
         }
         else
         {
             await next();
         }
     });
 }

Echo()

private Timer _timer;
WebSocket _webSocket;
 private async Task Echo()
 {
     OnValueChanged += Startup_OnValueChanged;

     _timer = new Timer(new TimerCallback((state) => ++X));
     var period = TimeSpan.FromMilliseconds(2000);
     _timer.Change(TimeSpan.Zero, period);

     var buffer = new byte[1024 * 4];
     WebSocketReceiveResult result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
     while (!result.CloseStatus.HasValue)
     {
         result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
     }
     await _webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
 }
OnValueChanged的值更改时,会触发

X

 int x = 0;
 public int X
 {
     get => x;
     set
     {
         if (x != value)
         {
             x = value;
             OnValueChanged(this, EventArgs.Empty);
         }
     }
 }

事件处理程序:

private async void Startup_OnValueChanged(object sender, EventArgs e)
{
    var buffer = new byte[1024 * 4];
    buffer = Encoding.ASCII.GetBytes(X.ToString());
    await _webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, buffer.Count()), WebSocketMessageType.Text, true, CancellationToken.None);
}

此工作解决方案的缺点是我无法在启动类中分离代码,因为我只能通过解释即将到来的请求来获取WebSocket。

总结一下:我想通过websocket(仅一个方向)更新网页的内容,但无法分离websocket代码,这与Startup类紧密相关。

*我是WebSockets编程的新手,并且是.NET Core业余爱好者,并且在发布问题之前对此主题进行了一些研究。

0 个答案:

没有答案