Reputation: 844
I have long-running ASP.NET Core API that I would like to present a progress bar on UI.
From the server-side, I know how many jobs will be done from the very beginning. Say, if I have 10 jobs and each job takes a second, this will be 10 seconds long progress bar.
The best I could find was https://github.com/DmitrySikorsky/AspNetCoreUploadingProgress, But it relies on saving the progress on Startup. Progress, which is static int. Wouldn't it mean there can be only one upload session at a time in the entire web application?
I wonder if I can do this with axios call:
return axios.post(
'/api/long-running-task',
{},
{
onUploadProgress: function(progressEvent) {
console.log("upload", progressEvent.loaded, progressEvent.total);
},
onDownloadProgress: function(progressEvent) {
console.log("download", progressEvent.loaded, progressEvent.total);
}
}
);
And if I do something properly from ASP.NET Core side, would I be able to communicate back to axios and trigger either onUploadProgress or onDownloadProgress?
What I tried:
[HttpPost]
[Route("long-running-task")]
public async Task<ActionResult> Run()
{
Response.StatusCode = 200;
Response.ContentType = "text/plain";
Response.ContentLength = 10;
var sw = new StreamWriter(Response.Body);
for (var i = 0; i < 10; i++)
{
await Task.Delay(1000);
await sw.WriteAsync("1");
await sw.FlushAsync();
}
return null;
}
axios writes one upload
log shortly after, and then one download
log 10 seconds later. No interim progress is received.
Upvotes: 3
Views: 5269
Reputation: 844
I found a way to make this work: specify ContentType to be text/event-stream
.
I believe it changes server side caching behavior so it should work on any browsers as along as axios is supported. Confirmed working on Chrome 81, Edge 44 and IE 11.
[HttpPost]
[Route("long-running-task")]
public async Task<ActionResult> Run()
{
Response.StatusCode = 200;
Response.ContentType = "text/event-stream";
Response.ContentLength = 10;
var sw = new StreamWriter(Response.Body);
for (var i = 0; i < 10; i++)
{
await Task.Delay(1000);
await sw.WriteAsync("1");
await sw.FlushAsync();
}
return Ok();
}
EDIT: at the end, return Ok() instead of null. If you don't have any jobs, returning null will throw an exception.
Upvotes: 5
Reputation: 19514
Upload and download status wont help you with your task since it will take progress of request size.
What you need to do is on asp.net core side:
job/start
api which returns you some kind of keyjob/progress/id
api which will tell you how much you progressThen inside of your axios call start job get id, then each N seconds call status to see how much your job progressed.
Other option look into signalR steps will be the same the only you wont need to call status api every N seconds you will be able to push back from server you job status.
Upvotes: 0