bunny1985
bunny1985

Reputation: 772

c# PushStreamContent flush bug?

Did anyone of you tried to use PushStreamContent with WebApi? I've noticed strange behavior. Here is my code ( crappy one I know - Just Testing )

public class MsgModel
    {
        public MsgModel()
        {
            this.date = DateTime.Now.ToShortTimeString();
        }
        public string msg { get; set; }
        public string date { get; set; }
    }
    [RoutePrefix("rx")]
    public class RxController : ApiController
    {
        private static ConcurrentDictionary< string, Stream> clients = new ConcurrentDictionary< string, Stream>();

        [HttpGet]
        [Route("subscribe")]
        public async Task<HttpResponseMessage> Subscribe(HttpRequestMessage request)
        {
            var response = request.CreateResponse();
            response.Content = new PushStreamContent(async (a, b, c) => { await OnStreamAvailable(a, b, c); }, "text/event-stream");

            return response;
        }

        private static  void WriteEventToStreamAsync(Guid id , string type , string data , Stream stream )
        {
            try
            {
                StreamWriter sw = new StreamWriter(stream);

                sw.Write("event: " + type + "\n");
                sw.Write("id: " + Guid.NewGuid() + "\n");
                sw.Write("data: " + data + "\n\n");
                sw.Flush();
                stream.Flush();
            }
            catch(Exception e)
            {
                StreamWriter ignore;
                //clients.TryRemove( out ignore);
            }
        }



        [HttpPost]
        [Route("msg")]
        public IHttpActionResult Push(MsgModel model)
        {

            foreach (var clientPair in clients)
            {
                var client = clientPair.Value;
                try
                {

                    WriteEventToStreamAsync(Guid.NewGuid(), "push", JsonConvert.SerializeObject(model), client);
                }
                catch (Exception)
                {
                    Stream ignore;
                    clients.TryRemove(clientPair.Key ,out  ignore);
                }
            }
            return Ok();
        }




        private async Task OnStreamAvailable(Stream stream, HttpContent content, TransportContext context)
        {


            WriteEventToStreamAsync(Guid.NewGuid(), "welcome", JsonConvert.SerializeObject(new MsgModel() { msg = "Welcome" }), stream);
            var userName = this.User.Identity.Name;
            Stream ignore;
            clients.TryRemove(userName,out  ignore);
            clients.TryAdd(this.User.Identity.Name  , stream);
        }
    } 

And now... It seems that everything works, but in fact when I try to consume it on frontend I get most of the time one message behind current state. So at first I have empty stream ( on frontend side), then after calling "Push" Method I Get "Welcome" Msg and so on. The behavior remains the same when I'm using async methods. Moreover its not deterministic. Sometimes I get All messages, sometimes one behind.

Pls. don;t kill me for this question ;) I might be missing something.

Upvotes: 3

Views: 765

Answers (1)

Jonathan Amend
Jonathan Amend

Reputation: 12815

I don't quite understand why, but it works for me when sending \r\n\r\n (even though the spec says \n\n). For some reason, I only have this problem with IIS, because I don't need this workaround in IIS Express or OWIN self host.

sw.Write("data: " + data + "\r\n\r\n");
sw.Flush();

Upvotes: 2

Related Questions