public async Task <string> EventSource()
        {
            // use the event stream content type, as per specification
            HttpContext.Response.ContentType = "text/event-stream";

            // get the last event id out of the header
            string lastEventIdString = HttpContext.Request.Headers["Last-Event-ID"].FirstOrDefault();
            int    temp;
            int?   lastEventId = null;

            if (lastEventIdString != null && int.TryParse(lastEventIdString, out temp))
            {
                lastEventId = temp;
            }

            string remoteIp = HttpContext.Connection.RemoteIpAddress.ToString();


            // open the current request stream for writing.
            // Use UTF-8 encoding, and do not close the stream when disposing.
            using (var clientStream = new StreamWriter(HttpContext.Response.Body, Encoding.UTF8, 1024, true)
            {
                AutoFlush = true
            }) {
                // subscribe to the heartbeat event. Elsewhere, a timer will push updates to this event periodically.
                using (EventSubscription <EventSourceUpdate> subscription = eventsService.SubscribeTo <EventSourceUpdate>("heartbeat")) {
                    try {
                        logger.LogInformation($"Opened event source stream to address: {remoteIp}");

                        await clientStream.WriteLineAsync($":connected {DateTimeOffset.Now.ToString("o")}");

                        // If a last event id is given, pump out any intermediate events here.
                        if (lastEventId != null)
                        {
                            // We're not doing anything that stores events in this heartbeat demo,
                            // so do nothing here.
                        }

                        // start pumping out events as they are pushed to the subscription queue
                        while (true)
                        {
                            // asynchronously wait for an event to fire before continuing this loop.
                            // this is implemented with a semaphore slim using the async wait, so it
                            // should play nice with the async framework.
                            EventSourceUpdate update = await subscription.WaitForData();

                            // push the update down the request stream to the client
                            if (update != null)
                            {
                                string updateString = update.ToString();
                                await clientStream.WriteAsync(updateString);
                            }

                            if (HttpContext.RequestAborted.IsCancellationRequested == true)
                            {
                                break;
                            }
                        }
                    }
                    catch (Exception e) {
                        // catch client closing the connection
                        logger.LogInformation($"Closed event source stream from {remoteIp}. Message: {e.Message}");
                    }
                }
            }

            return(":closed");
        }