我有一个 RESTful Web API 2 解决方案,其方法是从 AngularJS 应用程序调用的。我想添加对从服务器端 API 向客户端逻辑发送通知的支持。但是,从未调用通过调用 Javascript 中的 addEventListener 设置的消息和打开方法。 Web API Controller 如下:
namespace Controllers
{
public class EventController : ApiController
{
private static readonly List<StreamWriter> ConnectedClients = new List<StreamWriter>();
private static Timer _timer;
public EventController()
{
if(_timer == null)
_timer = new Timer(TimerCallback, null, 0, 2000);
}
public static void OnStreamAvailable(Stream stream, HttpContent headers, TransportContext context)
{
var streamwriter = new StreamWriter(stream);
ConnectedClients.Add(streamwriter);
}
private static void MessageCallback(Message m)
{
foreach (var subscriber in ConnectedClients)
{
try
{
subscriber.Write("data: {0}\n\n", JsonConvert.SerializeObject(m));
subscriber.Flush();
}
catch (Exception ex)
{
// This probably means the user has disconnected
ConnectedClients.Remove(subscriber);
}
}
}
private static void TimerCallback(object state)
{
var m = new Message
{
Date = DateTime.Now.ToUniversalTime().ToString("u"),
Text = "Hello World!"
};
MessageCallback(m);
}
[HttpGet]
public HttpResponseMessage Get(HttpRequestMessage request)
{
// New subscription request
var response = request.CreateResponse();
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Cache-Control", "no-cache, must-revalidate");
response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>)OnStreamAvailable, "text/event-stream");
return response;
}
}
}
请注意,我还为我的 HttpGet 方法尝试了以下方法:
public HttpResponseMessage Get()
{
// New subscription request
var response = Request.CreateResponse();
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Cache-Control", "no-cache, must-revalidate");
response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>)OnStreamAvailable, "text/event-stream");
return response;
}
Javascript:
if (!!window.EventSource) {
var eventSource = new EventSource(GlobalConfig.apiRoot + 'Event');
eventSource.addEventListener('open', function (e) {
console.log("open");
}, false);
eventSource.addEventListener('error', function (e) {
console.log("error");
}, false);
eventSource.addEventListener('message', function (e) {
console.log('message');
}, false);
} else {
// not supported!
}
我在 Visual Studio 2013 下通过 IISExpress 运行它。但是我也在 IIS 8 下进行了测试,结果相同。所有测试均在 36.0.1985.143 m 版本的 Google Chrome 中完成。我可以验证的是:
- 调用 Web API 中的 Get 方法。
- 计时器(我设置它只是为了测试)按预期运行并调用 TimerCallback 方法。然后运行 MessageCallback。
- 如果我在打开 Chrome 的情况下关闭 Visual Studio/IISExpress,则会调用 Javascript 中的错误方法并出现 net::ERR_CONNECTION_REFUSED 错误。
- 同样,如果我关闭运行 Visual Studio/IISExpress 的浏览器,则会在 MessageCallback Controller 方法中抛出 HttpException。
也就是说,似乎确实存在某种联系,但我不明白为什么从不在 Javascript 中调用消息和打开处理程序。
为了检查 AngularJS 中是否没有任何影响,我将我的 Javascript 移到了静态 HTML 页面。 Chrome 控制台中记录了以下内容:
Request URL:http://localhost/.../api/Event
Request Headers
Provisional headers are shown
Accept:text/event-stream
Cache-Control:no-cache
Referer:http://localhost/.../test.html
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36
请求的状态始终为“待处理”。但是,鉴于连接保持打开状态,这正是我所期望的。
我们将不胜感激地收到有关获得此功能的任何建议。
最佳答案
我认为正确的格式是:
subscriber.Write("event: message\n");
subscriber.Write("data: {0}\n\n");
事件监听器仅响应包含事件消息名称(在本例中为 message
)的事件。这意味着服务器能够发送可以单独订阅的多个事件类型。
关于c# - 从未从 Web API 2 调用的 HTML5 EventSource onmessage,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25374782/