Skip to content

Commit 8cf446a

Browse files
committed
SSE return types /2
1 parent 48463b2 commit 8cf446a

File tree

8 files changed

+150
-6
lines changed

8 files changed

+150
-6
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
public record HeartRateRecord(DateTime Timestamp, int HeartRate)
2+
{
3+
public static HeartRateRecord Create(int heartRate) => new(DateTime.UtcNow, heartRate);
4+
}

aspnetcore/fundamentals/minimal-apis/10.0-samples/MinimalServerSentEvents/Program.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ async IAsyncEnumerable<string> GetHeartRate(
2525
// <snippet_json>
2626
app.MapGet("/json-item", (CancellationToken cancellationToken) =>
2727
{
28-
async IAsyncEnumerable<HearRate> GetHeartRate(
28+
async IAsyncEnumerable<HeartRateRecord> GetHeartRate(
2929
[EnumeratorCancellation] CancellationToken cancellationToken)
3030
{
3131
while (!cancellationToken.IsCancellationRequested)
3232
{
3333
var heartRate = Random.Shared.Next(60, 100);
34-
yield return HearRate.Create(heartRate);
34+
yield return HeartRateRecord.Create(heartRate);
3535
await Task.Delay(2000, cancellationToken);
3636
}
3737
}
@@ -64,7 +64,3 @@ async IAsyncEnumerable<SseItem<int>> GetHeartRate(
6464

6565
app.Run();
6666

67-
public record HearRate(DateTime Timestamp, int HeartRate)
68-
{
69-
public static HearRate Create(int heartRate) => new(DateTime.UtcNow, heartRate);
70-
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
### Support for Server-Sent Events (SSE)
2+
3+
ASP.NET Core now supports returning a [ServerSentEvents](xref:System.Net.ServerSentEvents) result using the [TypedResults.ServerSentEvents](https://source.dot.net/#Microsoft.AspNetCore.Http.Results/TypedResults.cs,051e6796e1492f84) API. This feature is supported in both Minimal APIs and controller-based apps.
4+
5+
Server-Sent Events is a server push technology that allows a server to send a stream of event messages to a client over a single HTTP connection. In .NET the event messages are represented as [`SseItem<T`>`](/dotnet/api/system.net.serversentevents.sseitem-1) objects, which may contain an event type, an ID, and a data payload of type `T`.
6+
7+
The [TypedResults](xref:Microsoft.AspNetCore.Http.TypedResults) class has a new static method called [ServerSentEvents](https://source.dot.net/#Microsoft.AspNetCore.Http.Results/TypedResults.cs,ceb980606eb9e295) that can be used to return a `ServerSentEvents` result. The first parameter to this method is an `IAsyncEnumerable<SseItem<T>>` that represents the stream of event messages to be sent to the client.
8+
9+
The following example illustrates how to use the `TypedResults.ServerSentEvents` API to return a stream of heart rate events as JSON objects to the client:
10+
11+
:::code language="csharp" source="~/fundamentals/minimal-apis/10.0-samples/MinimalServerSentEvents/Program.cs" id="snippet_json" :::
12+
13+
For more information, see:
14+
15+
-
16+
- [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events) on MDN.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0-*" />
11+
</ItemGroup>
12+
13+
</Project>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
@baseUrl = http://localhost:5201/HeartRate
2+
3+
### Connect to SSE stream
4+
# This request will open an SSE connection that stays open
5+
GET {{baseUrl}}/string-item
6+
Accept: text/event-stream
7+
8+
###
9+
GET {{baseUrl}}/json-item
10+
Accept: text/event-stream
11+
12+
###
13+
14+
GET {{baseUrl}}/sse-item
15+
Accept: text/event-stream
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using System.Runtime.CompilerServices;
3+
using System.Net.ServerSentEvents;
4+
5+
[ApiController]
6+
[Route("[controller]")]
7+
8+
public class HeartRateController : ControllerBase
9+
{
10+
// /HeartRate/json-item
11+
[HttpGet("json-item")]
12+
public IResult GetHeartRateJson(CancellationToken cancellationToken)
13+
{
14+
async IAsyncEnumerable<HearRate> StreamHeartRates(
15+
[EnumeratorCancellation] CancellationToken cancellationToken)
16+
{
17+
while (!cancellationToken.IsCancellationRequested)
18+
{
19+
var heartRate = Random.Shared.Next(60, 100);
20+
yield return HearRate.Create(heartRate);
21+
await Task.Delay(2000, cancellationToken);
22+
}
23+
}
24+
25+
return TypedResults.ServerSentEvents(StreamHeartRates(cancellationToken), eventType: "heartRate");
26+
}
27+
28+
// /HeartRate/string-item
29+
[HttpGet("string-item")]
30+
31+
public IResult GetHeartRateString(CancellationToken cancellationToken)
32+
{
33+
async IAsyncEnumerable<string> GetHeartRate(
34+
[EnumeratorCancellation] CancellationToken cancellationToken)
35+
{
36+
while (!cancellationToken.IsCancellationRequested)
37+
{
38+
var heartRate = Random.Shared.Next(60, 100);
39+
yield return $"Hear Rate: {heartRate} bpm";
40+
await Task.Delay(2000, cancellationToken);
41+
}
42+
}
43+
44+
return TypedResults.ServerSentEvents(GetHeartRate(cancellationToken), eventType: "heartRate");
45+
}
46+
47+
// /HeartRate/sse-item
48+
[HttpGet("sse-item")]
49+
50+
public IResult GetHeartRateSSE(CancellationToken cancellationToken)
51+
{
52+
async IAsyncEnumerable<SseItem<int>> GetHeartRate(
53+
[EnumeratorCancellation] CancellationToken cancellationToken)
54+
{
55+
while (!cancellationToken.IsCancellationRequested)
56+
{
57+
var heartRate = Random.Shared.Next(60, 100);
58+
yield return new SseItem<int>(heartRate, eventType: "heartRate")
59+
{
60+
ReconnectionInterval = TimeSpan.FromMinutes(1)
61+
};
62+
await Task.Delay(2000, cancellationToken);
63+
}
64+
}
65+
66+
return TypedResults.ServerSentEvents(GetHeartRate(cancellationToken));
67+
}
68+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
public record HearRate(DateTime Timestamp, int HeartRate)
2+
{
3+
public static HearRate Create(int heartRate) => new(DateTime.UtcNow, heartRate);
4+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
var builder = WebApplication.CreateBuilder(args);
3+
4+
// Add services to the container.
5+
6+
builder.Services.AddControllers();
7+
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
8+
builder.Services.AddOpenApi();
9+
10+
var app = builder.Build();
11+
12+
// Configure the HTTP request pipeline.
13+
if (app.Environment.IsDevelopment())
14+
{
15+
app.MapOpenApi();
16+
}
17+
18+
app.UseHttpsRedirection();
19+
20+
app.UseAuthorization();
21+
22+
23+
app.MapControllers();
24+
25+
app.MapGet("/", () => Results.Redirect("/HeartRate/json-item"));
26+
27+
28+
app.Run();

0 commit comments

Comments
 (0)