For this post, we're going to explore a way to stream data to the client using a Web Api and C#.
Picture this requirement, you need to process an array of data, lets say of a 100 items, once each item is processed, the api should return data to the client, without SignalR.
To do this, in this example, we will have a worker that will return a IAsyncEnumerable
and between each iteration, the method will wait between 5 to 10 seconds.
//Service.cs
private static readonly Random _random = new Random();
public async IAsyncEnumerable<int> GetData(int amount)
{
foreach(var item in Enumerable.Range(0, amount))
{
// Wait a random amount of time to simulate some work.
var secondsToWait = _random.Next(5,10);
await Task.Delay(Timespan.FromSeconds(secondsToWait));
yield return item;
}
}
With the simulated service in place, we can move on to the Controller
. For the endpoint, we're going to have an async Task
Get
method that will write the result to the Response and send it for every item it was processed.
// StreamController.cs
private readonly IService _service;
public StreamController(IService service)
{
_service = service;
}
[HttpGet("{amount:int:min(1)}")]
public async Task GetStreamData(int amount)
{
// Set Content-Type to text/event-stream
Response.Headers.Add("Content-Type", "text/event-stream");
await foreach(var data in _service.GetData(amount))
{
// this can be anything, even just a json object
string dataItem = $"data: {data}\n\n";
// Convert the text to a byte array
var utf8DataitemBytes = Encoding.UTF8.GetBytes(dataItem);
// Write the byte array to the HttpResponse
await Response.Body.WriteAsync(utf8DataitemBytes, 0, utf8DataitemBytes.Length);
// Push
await Response.Body.FlushAsync();
}
}
When the endpoint is called, it'll send a new "line" of data instead of waiting for all items to be processed to be sent at once.
Top comments (2)
HTTP is using TCP/IP (for now mainly). So the please fix that part "without TCP/IP" as it's missleading. And it's not returning HttpRequest it's using it to get the response object and write to it.
Thanks for the feedback!
Yes, reading through that part again it was misleading.