I have an API that allows a user to run a back end process and get the response as a series of text lines. The controller is calling this:
public async IEnumerable<string> Execute(Info[] infoArray)
{
foreach(var info in infoArray)
{
try
{
var result = await ProcessInfo(info);
yield return result;
}
catch(ProcessException e)
{
yield return e.Message;
}
}
So ProcessInfo
can take some time to execute, but I want the UI to have a running update of the results.
So, basically I want the controller to return a stream, and send one string at a time as it evaluates the IEnumerable
, and then on the Typescript side (I am currently using Axios.get
requests) get it one string at a time so that I can update a GUI with a running log.
I spent several hours digging around on Google and Stackoverflow and couldn’t find a good example to follow. What is the best approach?
2
Answers
One possible approach is to use the IAsyncEnumerable feature that is supported in ASP.NET Core 6. This feature allows you to stream JSON responses from the controller action to the response formatter, without buffering the data in memory. You can also use EF Core to query the data asynchronously and return an IAsyncEnumerable from your ProcessInfo method.
To use this feature, you need to change your controller action to return an IAsyncEnumerable instead of an IEnumerable. For example:
On the Typescript side, you need to use a library that can handle streaming JSON responses, such as Oboe.js.
This library allows you to parse the JSON response as a stream and handle each item as it arrives.
Your controller should return an
IAsyncEnumerable<string>
or aContentResult
with a specific media type (text/event-stream
).You may need to disable request buffering and enable streaming to allow for a continuous flow of data like that
In Angular service or component, create an
EventSource
instance that connects to the streaming endpoint of API.Inject the service into component and subscribe to the
startStream
method.Update your component’s view as new data arrives