An open API service indexing awesome lists of open source software.

https://github.com/fkucukkara/server-sent-events

This project demonstrates how to implement Server-Sent Events (SSE) using the new features introduced in .NET 10.
https://github.com/fkucukkara/server-sent-events

csharp net10 netcore-webapi server-sent-events sse

Last synced: 17 days ago
JSON representation

This project demonstrates how to implement Server-Sent Events (SSE) using the new features introduced in .NET 10.

Awesome Lists containing this project

README

          

# Server-Sent Events (SSE) with .NET 10

This project demonstrates how to implement **Server-Sent Events (SSE)** using the new features introduced in **.NET 10**. It's a simple educational proof-of-concept that shows real-time heart rate monitoring using minimal APIs.

## ๐ŸŽฏ What is Server-Sent Events (SSE)?

Server-Sent Events is a web standard that allows a server to push data to a web page in real-time. Unlike WebSockets, SSE is unidirectional (server-to-client only) and simpler to implement for scenarios where you only need to send data from server to client.

> **Note:** This project uses "server-sent-events" (with hyphens) as the standard naming convention for SSE, which is the correct terminology according to the W3C specification.

## ๐Ÿ†• What's New in .NET 10

.NET 10 introduces native support for Server-Sent Events with:

- **`SseItem`** - Strongly-typed SSE item representation
- **`TypedResults.ServerSentEvents()`** - Built-in minimal API support
- **`System.Net.ServerSentEvents`** namespace - Complete SSE framework

## ๐Ÿ“ Project Structure

```
server-sent-events/
โ”œโ”€โ”€ API/
โ”‚ โ”œโ”€โ”€ API.csproj # .NET 10 project file
โ”‚ โ”œโ”€โ”€ Program.cs # Main application with SSE endpoint
โ”‚ โ”œโ”€โ”€ API.http # HTTP test requests
โ”‚ โ””โ”€โ”€ Properties/
โ”‚ โ””โ”€โ”€ launchSettings.json # Development settings
โ”œโ”€โ”€ global.json # .NET SDK version pinning
โ”œโ”€โ”€ server-sent-events.sln # Solution file
โ””โ”€โ”€ README.md # This file
```

## ๐Ÿš€ Features

- โœ… **Pure API** - No UI, just the SSE endpoint
- โœ… Real-time heart rate simulation (60-100 BPM)
- โœ… Native .NET 10 SSE implementation
- โœ… Minimal API with OpenAPI documentation
- โœ… Proper cancellation token handling
- โœ… Automatic reconnection support
- โœ… Type-safe event streaming
- โœ… Ready for integration with any frontend

## ๐Ÿ“‹ Prerequisites

- **.NET 10 SDK** - [Download here](https://dotnet.microsoft.com/download/dotnet/10.0)
- **Visual Studio 2026** or **VS Code** (optional)

## ๐Ÿ› ๏ธ Getting Started

### 1. Clone the Repository

```bash
git clone https://github.com/fkucukkara/server-sent-events.git
cd server-sent-events
```

### 2. Verify .NET 10 Installation

```bash
dotnet --version
# Should show: 10.0.100 or later
```

### 3. Restore Dependencies

```bash
dotnet restore
```

### 4. Build the Project

```bash
dotnet build
```

### 5. Run the Application

```bash
cd API
dotnet run
```

The application will start at `https://localhost:7144`

## ๐Ÿ”Œ API Endpoints

| Endpoint | Method | Description | Response Type |
|----------|--------|-------------|---------------|
| `/string-item` | GET | SSE stream of heart rate data as plain strings | `text/event-stream` |
| `/json-item` | GET | SSE stream of heart rate data as JSON objects | `text/event-stream` |
| `/sse-item` | GET | SSE stream using strongly-typed `SseItem` with reconnection metadata | `text/event-stream` |
| `/openapi/v1.json` | GET | OpenAPI specification | `application/json` |

## ๐Ÿงช Testing the SSE Endpoint

### Option 1: Using VS Code REST Client

Open `API/API.http` and click "Send Request" on the SSE endpoint:

```http
GET https://localhost:7144/sse-item
Accept: text/event-stream
Cache-Control: no-cache
```

### Option 2: Using Browser

Navigate to: `https://localhost:7144/sse-item`

You'll see a continuous stream of heart rate data:

```
event: heartRate
data: 75

event: heartRate
data: 82

event: heartRate
data: 68
```

### Option 3: Using curl

```bash
curl -N -H "Accept: text/event-stream" https://localhost:7144/sse-item
```

### Option 4: Using JavaScript Client

Create your own HTML file to test the SSE endpoint:

```html

Heart Rate Monitor

Real-time Heart Rate


Connecting...


const eventSource = new EventSource('https://localhost:7144/sse-item');

eventSource.addEventListener('heartRate', function(event) {
document.getElementById('heartRate').innerHTML =
`โค๏ธ Heart Rate: ${event.data} BPM`;
});

eventSource.onerror = function(event) {
console.error('SSE error:', event);
};

```

## ๐Ÿ“ Code Explanation

### Pattern 1 โ€” Plain String Events

```csharp
app.MapGet("/string-item", (CancellationToken cancellationToken) =>
{
async IAsyncEnumerable GetHeartRate(
[EnumeratorCancellation] CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var heartRate = Random.Shared.Next(60, 100);
yield return $"Heart Rate: {heartRate} bpm";
await Task.Delay(2000, cancellationToken);
}
}

return TypedResults.ServerSentEvents(GetHeartRate(cancellationToken), eventType: "heartRate");
});
```

### Pattern 2 โ€” JSON Object Events

```csharp
app.MapGet("/json-item", (CancellationToken cancellationToken) =>
{
async IAsyncEnumerable GetHeartRate(
[EnumeratorCancellation] CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var heartRate = Random.Shared.Next(60, 100);
yield return HeartRateRecord.Create(heartRate);
await Task.Delay(2000, cancellationToken);
}
}

return TypedResults.ServerSentEvents(GetHeartRate(cancellationToken), eventType: "heartRate");
});

record HeartRateRecord(int HeartRate, DateTime Timestamp)
{
public static HeartRateRecord Create(int heartRate) => new(heartRate, DateTime.UtcNow);
}
```

### Pattern 3 โ€” Strongly-Typed `SseItem` with Metadata

```csharp
app.MapGet("/sse-item", (CancellationToken cancellationToken) =>
{
async IAsyncEnumerable> GetHeartRate(
[EnumeratorCancellation] CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var heartRate = Random.Shared.Next(60, 100);
yield return new SseItem(heartRate, eventType: "heartRate")
{
ReconnectionInterval = TimeSpan.FromMinutes(1)
};
await Task.Delay(2000, cancellationToken);
}
}

return TypedResults.ServerSentEvents(GetHeartRate(cancellationToken));
});
```

### Key Components

1. **`IAsyncEnumerable`** - Async stream of events; `T` can be `string`, a record, or `SseItem`
2. **`TypedResults.ServerSentEvents()`** - Converts the stream to an SSE (`text/event-stream`) response
3. **`[EnumeratorCancellation]`** - Proper cancellation token propagation through async enumerables
4. **`eventType`** - Custom event type for client-side filtering via `addEventListener('heartRate', handler)`
5. **`ReconnectionInterval`** - Instructs the client how long to wait before reconnecting (only on `SseItem`)

## โš™๏ธ Configuration

### global.json

Ensures the project uses .NET 10 SDK:

```json
{
"sdk": {
"version": "10.0.300",
"rollForward": "latestPatch"
}
}
```

### Project File (API.csproj)

```xml


net10.0
enable
enable



```

## ๐ŸŒŸ SSE vs WebSockets

| Feature | Server-Sent Events | WebSockets |
|---------|-------------------|------------|
| **Direction** | Server โ†’ Client only | Bidirectional |
| **Protocol** | HTTP | WebSocket Protocol |
| **Complexity** | Simple | More complex |
| **Auto-reconnect** | Built-in | Manual implementation |
| **Firewall-friendly** | Yes (HTTP) | Sometimes blocked |
| **Use cases** | Live feeds, notifications | Chat, gaming, collaboration |

## ๐ŸŽ“ Educational Objectives

This POC demonstrates:

1. **Modern .NET 10 SSE APIs** - Latest framework features
2. **Minimal APIs** - Simplified web API development
3. **Async Streaming** - `IAsyncEnumerable` patterns
4. **Real-time Communication** - Server-to-client data push
5. **Cancellation Patterns** - Proper resource cleanup
6. **Type Safety** - Strongly-typed event streaming

## ๐Ÿš€ Next Steps & Extensions

### Beginner Extensions
- Add different event types (temperature, pressure, etc.)
- Implement event filtering on the client side
- Add basic error handling and retry logic

### Intermediate Extensions
- Add authentication and authorization
- Implement multiple SSE endpoints
- Add persistent data storage (Entity Framework)
- Create a web dashboard with charts

### Advanced Extensions
- Add horizontal scaling with Redis
- Implement SSE with SignalR fallback
- Add monitoring and logging
- Performance testing and optimization

## ๐Ÿ“š Additional Resources

- [Microsoft Docs - SSE in Minimal APIs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/responses?view=aspnetcore-10.0#server-sent-events-sse)
- [MDN - Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
- [.NET 10 Preview Features](https://devblogs.microsoft.com/dotnet/)
- [Minimal APIs Documentation](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis)

## License
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

This project is licensed under the MIT License, which allows you to freely use, modify, and distribute the code. See the [`LICENSE`](LICENSE) file for full details.