// Message.cs
public record Message(Guid id, string data)
{
public override string ToString() => $"id: {id}\ndata: {data}\n";
}The Message record will handle the id and data that will
be send via event stream. It also overrides the default ToString()
method in order to print Message's data in a streamable format.
Since the server will be handling the HTTP requests in parallel. We need a thread safe channel to communicate between theses request handlers.
A System.Threading.Channels.Channel class give us a Writter and
Reader allowing to implement a Producer/Consumer pattern.
// Program.cs
var channel = Channel.CreateUnbounded<Message>();
builder.Services.AddSingleton(channel);Lets implement a endpoint to handling income messages and write them
in our Channel.
// Program.cs
app.MapPost("/send", async ([FromServices] Channel<Message> _channel, [FromQuery] string message) =>
{
await _channel.Writer.WriteAsync(new Message(id: Guid.NewGuid(), data: message));
return Results.Ok();
});// Program.cs
app.MapGet("/event", async ([FromServices] Channel<Message> _channel, HttpContext context) =>
{
Console.WriteLine("Client listening");
context.Response.Headers.CacheControl = "no-store";
context.Response.Headers.ContentType = "text/event-stream";
while (await _channel.Reader.WaitToReadAsync())
{
while (_channel.Reader.TryRead(out Message? message))
{
await context.Response.WriteAsync(message.ToString() + '\n');
await context.Response.Body.FlushAsync();
}
}
});The code above will open an event-stream connection type and than
will wait for the Reader to get new messages.
When a new Message cames the server will write it to the response stream.
// Program.cs
app.UseDefaultFiles();
app.UseStaticFiles();// wwwroot/index.html
<html>
<head>
<title>SEE Test</title>
</head>
<body>
<h1>Listenig for events:</h1>
<ul id="list">
</ul>
<script>
const evtSource = new EventSource("/event");
console.log(evtSource);
evtSource.onmessage = (event) => {
console.log("New event:", event)
const newElement = document.createElement("li");
const eventList = document.getElementById("list");
newElement.textContent = `message: ${event.data}`;
eventList.appendChild(newElement);
};
</script>
</body>
</html>