我正在使用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业余爱好者,并且在发布问题之前对此主题进行了一些研究。