I have an action in controller in my ASP.NET Core Web API that uploads and processes a file. It's okay when file is small, but what if the file will be large? I want this action to execute asynchronously, so I defined method as async
, its return value is just Task
to be awaitable, and inserted continuous operations in await Task.Run(() => ...)
blocks, made the action also async
and call this method with await
keyword, but, in fact, this action doesn't return after calling this method. I've tried to upload large file, and have had to wait until file is completely uploaded and processed. So, what should I do to make this action executed really asynchronously?

- 120
- 2
- 11
-
A method will not return immediately if it hits an `await` - `await` is a suspension point in the execution of the method until the `await`ed `Task` completes. – trashr0x Sep 04 '18 at 08:24
-
you should use async Task
please visit https://stackoverflow.com/questions/41953102/using-async-await-or-task-in-web-api-controller-net-core – Hamid Karimi Sep 04 '18 at 08:28 -
So, it is executed in a different task, but I still have to wait for it? How can I make this task background without waiting for it? – Viacheslav Sep 04 '18 at 08:30
-
As i mentioned in question description, I've made the action async, respectively, I've also made its return value a `Task
` – Viacheslav Sep 04 '18 at 08:32
2 Answers
The calling side of your Web Api project has no idea of C# details, of what a Task
is or await
means. It might be C# or JS or even PHP or a person that typed your URL in a browser bar.
Your Web Api will by default (and should!) wait until the whole processing is done and then give a signal that is was successful. This is generally done through a status code as return value.
Now the client calling your API does not have to be stuck waiting for that. But that's client side programming. You cannot really do anything in your API to solve the client's problem with that.
Otherwise, you could make your API just put the file in a processing queue to be processed by a different piece of software later. But that would need another architecture, because now the caller needs to be notified of success of failure (or result in general) when it's not longer connected to your API, so you'd need callbacks.

- 75,013
- 26
- 93
- 142
-
Thanks! Could you recommend some resources to learn about the processing queue in ASP.NET Core? – Viacheslav Sep 04 '18 at 09:04
-
There is nothing specific to ASP.NET Core about queuing and processing. Your API writes the request to a queue (any kind you deem suitable... files, database, message queues, biztalk) and then another process operates on that queue and processes the items one by one. In the end, it needs a channel to notify the original caller. There is no single technology, but if you google "service bus", you might find some interesting topics. – nvoigt Sep 04 '18 at 10:01
-
I had this code for processing large files (this was for a large CSV file upload):
public async Task<IActionResult> UploadAsync(IFormFile file)
{
// Ensure the file has contents before processing.
if (file == null || file.Length == 0)
throw new ApiException("Csv file should not be null", HttpStatusCode.BadRequest)
.AddApiExceptionResponseDetails(ErrorTypeCode.ValidationError, ErrorCode.BelowMinimumLength, SOURCE);
// Ensure the file is not over the allowed limit.
if (file.Length > (_settings.MaxCsvFileSize * 1024))
throw new ApiException("Max file size exceeded, limit of " + _settings.MaxCsvFileSize + "mb", HttpStatusCode.BadRequest)
.AddApiExceptionResponseDetails(ErrorTypeCode.ValidationError, ErrorCode.ExceedsMaximumLength, SOURCE);
// Ensure the file type is csv and content type is correct for the file.
if (Path.GetExtension(file.FileName) != ".csv" ||
!Constants.CsvAcceptedContentType.Contains(file.ContentType.ToLower(CultureInfo.InvariantCulture)))
throw new ApiException("Csv content only accepted").AddApiExceptionResponseDetails(ErrorTypeCode.ValidationError, ErrorCode.Invalid, SOURCE);
// Read csv content.
var content = await file.ReadCsvAsync<OrderCsvResponseDto>() as CsvProcessedResponseDto<OrderCsvResponseDto>;
await ProcessBulkUpload(content);
// Return information about the csv file.
return Ok(content);
}
internal async Task ProcessBulkUpload(CsvProcessedResponseDto<OrderCsvResponseDto> content)
{
// do some processing...
}
There are web.config settings to increase the allowed time for file upload, this might help: How to increase the max upload file size in ASP.NET?
If your request exceeds the max timeout allowed data wont be returned to your caller as expected!
If you want to execute "fire-and-forget" code from C#, you can do this:
public static void FireAndForget(this Task task)
{
Task.Run(async() => await task).ConfigureAwait(false);
}
Javascript:
xhr.onreadystatechange = function() { xhr.abort(); }
AngularJS:
var defer = $q.defer();
$http.get('/example', { timeout: defer.promise }).success(callback);
// [...]
defer.resolve();
Some async/await tips for Js: http://2ality.com/2016/10/async-function-tips.html

- 6,819
- 17
- 71
- 131
-
I have almost same code, but it is still not asynchronous. The problem is that I have to wait for my method to be completed, and I want to send uploaded file into method, and just return `Ok` ActionResult from action. – Viacheslav Sep 04 '18 at 08:49
-
If you execute the call via script in the browser, do you see it timing out after a couple of minutes? I'd try the web.config setting and see if that helps :) – Rob Sep 04 '18 at 11:09
-
No, there's nothing in the browser. You see, code is correct and it executes correctly, I just want user not to wait it completely executed. – Viacheslav Sep 04 '18 at 12:26