Я изучаю 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, и провел некоторые исследованиятема до публикации вопроса.