Пример использования WebSocket для обновления данных клиента (односторонний) - PullRequest
0 голосов
/ 20 мая 2019

Я изучаю WebSockets с ASP.NET Core, большинство обучающих программ, на которые я наткнулся, объясняют это одинаково: клиент отправляет запрос, а сервер извлекает его в классе 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);
}

Недостатком этого рабочего решения является то, что я могу 't разделить код внутри класса запуска, так как я могу получить WebSocket только путем интерпретации поступающего запроса.

Чтобы обернуть все это: я хочу обновить содержимое веб-страницы через веб-сокет (в одном направлениитолько), но не может разделить код веб-сокета, он тесно связан с классом Startup.

* Я совершенно новичок в программировании WebSockets, и я любитель .NET Core, и провел некоторые исследованиятема до публикации вопроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...