vb.net 服务器使用标准 asp.net mvc 发送事件(事件源)导致错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35631938/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
server sent events (eventsource) with standard asp.net mvc causing error
提问by Yisroel M. Olewski
I am trying my hand at server-sent events, but I cannot get it to work within an MVC project (not WebAPI). I haven't found any good samples online.
我正在尝试处理服务器发送的事件,但我无法让它在 MVC 项目(不是 WebAPI)中工作。我在网上没有找到任何好的样品。
This is the server-side code I tried (including several failed attempts from various posts):
这是我尝试过的服务器端代码(包括来自各种帖子的几次失败尝试):
Function GetRows() as ActionResult
Dim ret = New HttpResponseMessage
' ret.Content.w
' Return ret
Response.ContentType = "text/event-stream"
Response.Write("data: " & "aaaa")
Dim flag = False
If flag Then
For i = 0 To 100
Response.Write("data: " & i)
Next
End If
Response.Flush()
'Return Content("Abv")
'Return Content(("data: {0}\n\n" & DateTime.Now.ToString(), "text/event-stream")
End Function
and here is the Javascript
这是 Javascript
var source = new EventSource("/Tool/GetRows");
source.onmessage = function (event) {
document.getElementById("messages").innerHTML += event.data + "<br>";
};
source.onerror = function (e) {
console.log(e);
};
For some reason it's always going into onerror, and there is no information there what type of error it might be.
出于某种原因,它总是进入onerror,并且那里没有信息它可能是什么类型的错误。
What am I doing wrong?
我究竟做错了什么?
BTW, I don't think this action should really return anything, since my understanding is it should only be writing to the stream string by string.
顺便说一句,我不认为这个动作真的应该返回任何东西,因为我的理解是它应该只写一个字符串一个字符串的流。
回答by Zev Spitz
EventSource expects a specific format, and will raise onerrorif the stream doesn't match that format -- a set of lines of field/value pairs separated by a :, with each line ending in a newline character:
EventSource需要特定的 format,onerror如果流不匹配该格式,则将引发- 一组由 a 分隔的字段/值对:行,每行以换行符结尾:
field: value
field: value
fieldcan be one of data,event,id,retry, or empty for a comment (will be ignored by EventSource).
field可以是一个data,event,id,retry,或空的注释(将被忽略的EventSource)。
datacan span multiple lines, but each of those lines must start with data:
data可以跨越多行,但每一行都必须以 data:
Each event trigger has to end with a double newline
每个事件触发器都必须以双换行符结尾
data: 1
data: second line of message
data: 2
data: second line of second message
Note: If you are writing in VB.NET, you can't use the \nescape sequence to write newlines; you have to use vbLfor Chr(10).
注意:如果是在VB.NET中编写,则不能使用\n转义序列来编写换行符;你必须使用vbLf或Chr(10)。
As an aside, EventSource is supposed to hold an open connection to the server. From MDN(emphasis mine):
顺便说一句,EventSource 应该保持与服务器的开放连接。来自MDN(强调我的):
The EventSourceinterface is used to receive server-sent events. It connects to a server over HTTP and receives events in text/event-stream format without closing the connection.
该EventSource的接口用于接收服务器发送的事件。它通过 HTTP 连接到服务器并在不关闭连接的情况下以文本/事件流格式接收事件。
Once control exits from an MVC controller method, the result will be packaged up and sent to the client, and the connection will be closed. Part of EventSource is that the client will try reopening the connection, which will once again be immediately closed by the server; the resulting close -> reopencycle can also be seen here.
一旦控制退出 MVC 控制器方法,结果将被打包并发送到客户端,并且连接将被关闭。EventSource 的一部分是客户端会尝试重新打开连接,这会再次被服务器立即关闭;由此产生的close -> reopen循环也可以在这里看到。
Instead of exiting from the method, the method should have some sort of loop that will be continuously writing to the Responsestream.
该方法不应退出该方法,而是应该具有某种循环,该循环将不断写入Response流。
Example in VB.NET
VB.NET 中的示例
Imports System.Threading
Public Class HomeController
Inherits Controller
Sub Message()
Response.ContentType= "text/event-stream"
Dim i As Integer
Do
i += 1
Response.Write("data: DateTime = " & Now & vbLf)
Response.Write("data: Iteration = " & i & vbLf)
Response.Write(vbLf)
Response.Flush
'The timing of data sent to the client is determined by the Sleep interval (and latency)
Thread.Sleep(1000)
Loop
End Sub
End Class
Example in C#
C# 中的示例
Client-side:
客户端:
<input type="text" id="userid" placeholder="UserID" /><br />
<input type="button" id="ping" value="Ping" />
<script>
var es = new EventSource('/home/message');
es.onmessage = function (e) {
console.log(e.data);
};
es.onerror = function () {
console.log(arguments);
};
$(function () {
$('#ping').on('click', function () {
$.post('/home/ping', {
UserID: $('#userid').val() || 0
});
});
});
</script>
Server-side:
服务器端:
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Web.Mvc;
using Newtonsoft.Json;
namespace EventSourceTest2.Controllers {
public class PingData {
public int UserID { get; set; }
public DateTime Date { get; set; } = DateTime.Now;
}
public class HomeController : Controller {
public ActionResult Index() {
return View();
}
static ConcurrentQueue<PingData> pings = new ConcurrentQueue<PingData>();
public void Ping(int userID) {
pings.Enqueue(new PingData { UserID = userID });
}
public void Message() {
Response.ContentType = "text/event-stream";
do {
PingData nextPing;
if (pings.TryDequeue(out nextPing)) {
Response.Write("data:" + JsonConvert.SerializeObject(nextPing, Formatting.None) + "\n\n");
}
Response.Flush();
Thread.Sleep(1000);
} while (true);
}
}
}

