Background and motivation
The System.Net.ServerSentEvents library added support for parsing SSE events. We should also add support for formatting SSE events on the server side, in a way that unlocks work for dotnet/aspnetcore#56172.
API Proposal
namespace System.Net.ServerSentEvents;
// Extends the existing type to support writing
public readonly struct SseItem<T>
{
- public SseItem(T data, string eventType);
+ public SseItem(T data, string? eventType);
public T Data { get; }
- public string EventType { get; }
+ public string? EventType { get; }
+ public string? EventId { get; init; }
}
public delegate T SseItemParser<out T>(string eventType, ReadOnlySpan<byte> data);
+public delegate byte[] SseItemFormatter<T>(T value);
+public sealed class SseFormatter
+{
+ public static SseFormatter Create<T>(IAsyncEnumerable<SseItem<string>> source);
+ public static SseFormatter Create<T>(IAsyncEnumerable<SseItem<T>> source, SseItemFormatter<T> itemFormatter);
+
+ public Task WriteToStreamAsync(Stream stream, CancellationToken cancellationToken = default);
+ public void WriteToStream(Stream stream, CancellationToken cancellationToken = default);
+}
API Usage
IAsyncEnumerable<SseItem<int>> source = ...;
SseFormatter formatter = SseFormatter.Create<int>(source, value => JsonSerializer.SerializeToBytes(value));
await formatter.WriteToStreamAsync(targetStream, cancellationToken);
Alternative Designs
The current SseItemFormatter delegate uses an allocating design, but which is simpler to use. Alternative designs would involve writing either to a Stream:
public delegate ValueTask SseItemFormatter<T>(Stream stream, T value);
But this would require wrapping the underlying stream in order to intercept potential line breaks. Alternatively, we could use an IBufferWriter<byte> which also composes better with PipeWriter targets:
public delegate void SseItemFormatter<T>(IBufferWriter<byte> writer, T value);
The downside of either approach is that it becomes harder to define formatters from the user's perspective:
SseFormatter formatter = SseFormatter.Create<int>(source, (bufferWriter, value) =>
{
var writer = new Utf8JsonWriter(bufferWriter);
return JsonSerializer.SerializeToBytes(bufferWriter, value);
});
Risks
No response
Background and motivation
The
System.Net.ServerSentEventslibrary added support for parsing SSE events. We should also add support for formatting SSE events on the server side, in a way that unlocks work for dotnet/aspnetcore#56172.API Proposal
namespace System.Net.ServerSentEvents; // Extends the existing type to support writing public readonly struct SseItem<T> { - public SseItem(T data, string eventType); + public SseItem(T data, string? eventType); public T Data { get; } - public string EventType { get; } + public string? EventType { get; } + public string? EventId { get; init; } } public delegate T SseItemParser<out T>(string eventType, ReadOnlySpan<byte> data); +public delegate byte[] SseItemFormatter<T>(T value); +public sealed class SseFormatter +{ + public static SseFormatter Create<T>(IAsyncEnumerable<SseItem<string>> source); + public static SseFormatter Create<T>(IAsyncEnumerable<SseItem<T>> source, SseItemFormatter<T> itemFormatter); + + public Task WriteToStreamAsync(Stream stream, CancellationToken cancellationToken = default); + public void WriteToStream(Stream stream, CancellationToken cancellationToken = default); +}API Usage
Alternative Designs
The current SseItemFormatter delegate uses an allocating design, but which is simpler to use. Alternative designs would involve writing either to a
Stream:But this would require wrapping the underlying stream in order to intercept potential line breaks. Alternatively, we could use an
IBufferWriter<byte>which also composes better withPipeWritertargets:The downside of either approach is that it becomes harder to define formatters from the user's perspective:
Risks
No response