server sent events (eventsource) with standard asp.net mvc causing error

我们两清 提交于 2019-11-27 04:56:43

EventSource expects a specific format, and will raise onerror if 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:

field: value
field: value

field can be one of data,event,id,retry, or empty for a comment (will be ignored by EventSource).

data can span multiple lines, but each of those lines must start with 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 \n escape sequence to write newlines; you have to use vbLf or Chr(10).


As an aside, EventSource is supposed to hold an open connection to the server. From MDN (emphasis mine):

The EventSource interface 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.

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 -> reopen cycle can also be seen here.

Instead of exiting from the method, the method should have some sort of loop that will be continuously writing to the Response stream.


Example in 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#

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);
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!