C# MVC 实现Server-Sent Events(ApiController案例)
(浏览器端) JS代码:
// 建立ServerSentEvents(服务器向浏览器推送信息,简称SSE) $(function () { if (typeof (EventSource) !== "undefined") { // 展示服务器推送内容的DOM var container = document.getElementById("SseContainer"); // 建立SSE通道 var es = new EventSource("/api/ServerSentEvents/BuildingSse"); // 监听SSE通道open事件 es.onopen = function (event) { container.innerHTML += "open<br/>"; } // 监听SSE接收到的服务端消息 es.onmessage = function (event) { container.innerHTML += event.data + "<br/>"; }; // 监听SSE通道error事件 es.onerror = function (event) { container.innerHTML += "error<br/>"; es.close(); } } else { console.log("浏览器不支持ServerSentEvents接口!"); } })
(服务器端)C# MVC Controller代码:
using Newtonsoft.Json; using System; using System.Collections.Concurrent; using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Web.Http; namespace CabinetMS.Controllers.WebApi { /// <summary> /// 自定义的SSE消息对象实体 /// </summary> public class SseMessageObject { public string MsgId { get; set; } public string MsgData { get; set; } } /// <summary> /// 以请求方式建立SSE通道 /// </summary> [RoutePrefix("api/ServerSentEvents")] public class ServerSentEventController : ApiController { // 接收浏览器请求,建立ServerSentEvents通道 [HttpGet, Route("BuildingSse")] public System.Net.Http.HttpResponseMessage BuildingSse(HttpRequestMessage request) { System.Net.Http.HttpResponseMessage response = request.CreateResponse(); response.Content = new System.Net.Http.PushStreamContent((Action<Stream, HttpContent, TransportContext>)WriteToStream, new MediaTypeHeaderValue("text/event-stream")); return response; } private static readonly ConcurrentDictionary<StreamWriter, StreamWriter> _streammessage = new ConcurrentDictionary<StreamWriter, StreamWriter>(); public void WriteToStream(Stream outputStream, HttpContent content, TransportContext context) { StreamWriter streamwriter = new StreamWriter(outputStream); _streammessage.TryAdd(streamwriter, streamwriter); } // 建立SSE通道后,其他Controller或程序调用此方法,可以向浏览器端主动推送消息 public static void SendSseMsg(SseMessageObject sseMsg) { MessageCallback(sseMsg); } // 设置向浏览器推送的消息内容 private static void MessageCallback(SseMessageObject sseMsg) { foreach (var subscriber in _streammessage.ToArray()) { try { subscriber.Value.WriteLine(string.Format("id: {0}\n", sseMsg.MsgId)); subscriber.Value.WriteLine(string.Format("data: {0}\n\n", sseMsg.MsgData)); subscriber.Value.Flush(); } catch { StreamWriter streamWriter; _streammessage.TryRemove(subscriber.Value, out streamWriter); } } } } }
(服务器端)成功建立SSE通道后,向浏览器推送消息:
// 服务端向网页端推送告警信息 var sseMsg = new SseMessageObject(); sseMsg.MsgId = "1101"; sseMsg.MsgData = "自定义告警消息"; ServerSentEventController.SendSseMsg(sseMsg);