I have this simple HTTPHandler which simply sets keep-alive to true and saves the response object to a list so we can write to it later. Then the global module further down has a timer which writes some content to the response object every 5 seconds, and that's where it's failing because the response object is no longer useable :
Imports System.Web
Imports System.Web.Services
Public Class a
Implements IHttpHandler
Public Sub ProcessRequest(context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/event-stream"
context.Response.CacheControl = "no-cache"
context.Response.Headers.Add("Connection", "keep-alive")
context.Response.Headers.Add("keep-alive", "")
' Register the client (response) with the global SSEClients list
RegisterClient(context.Response)
context.Response.Write("Session Started")
' Don't close the response stream after this method; let the client handle it
context.Response.BufferOutput = False
End Sub
Public ReadOnly Property IsReusable As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
Plus a global (static) module which is intended to feed strings every 5 seconds to the console application without requiring a new HTTPGET:
Friend Module Globals
Public SSEClients As New List(Of HttpResponse)
Public Index As Integer = 1
Private timer As New Threading.Timer(Sub() SendSSEEvent(), Nothing, 0, 5000)
Public Sub RegisterClient(response As HttpResponse)
SSEClients.Add(response)
End Sub
Private Sub SendSSEEvent()
Dim eventData As String = "data: Hello, World! " & Index & vbCrLf & vbCrLf
Index += 1
Dim ssecopy As New List(Of HttpResponse)(SSEClients)
For Each res As HttpResponse In ssecopy
Try
res.Write(eventData)
res.Flush()
Catch
Try
SSEClients.Remove(res)
Catch
End Try
End Try
Next
End Sub
End Module
And the client attempting to use this is a simple console application
Module Module1
Sub Main()
Console.WriteLine("Listening for SSE events. Press Enter to exit.")
Dim url As String = "https://localhost:44369/a.ashx"
Dim req As System.Net.HttpWebRequest = CType(System.Net.WebRequest.Create(url), System.Net.HttpWebRequest)
req.KeepAlive = True
req.Timeout = Threading.Timeout.Infinite
Using res As System.Net.HttpWebResponse = CType(req.GetResponse, System.Net.HttpWebResponse)
Using str As System.IO.Stream = res.GetResponseStream
Using rdr As New System.IO.StreamReader(str)
While True
Dim line As String = rdr.ReadLine()
If line IsNot Nothing Then
Console.WriteLine(line)
End If
End While
End Using
End Using
End Using
End Sub
End Module
This was working fine with an asp.net webform (i.e. an aspx page) but since I switched to a httphandler it has not worked since. The problem is that once the first "Session Started" has been written by the console application, the response object "res" in the client code is no longer useable, meaning that res.IsClientConnected always equal false.
How can I get this working so that the response object stays alive and the server can feed the client with strings every few seconds without making a new request ? Bard and chatgpt were not able to help despite a whole day spent trying different things.