Как сделать так, чтобы действие ASP.NET Core Web API выполнялось асинхронно? - PullRequest
0 голосов
/ 04 сентября 2018

У меня в контроллере ASP.NET Core Web API есть действие, которое загружает и обрабатывает файл. Это нормально, когда файл маленький, но что, если файл будет большим? Я хочу, чтобы это действие выполнялось асинхронно, поэтому я определил метод как async, его возвращаемое значение просто Task, чтобы быть ожидаемым, и вставил непрерывные операции в блоки await Task.Run(() => ...), сделал действие также async и вызвал этот метод с ключевым словом await, но на самом деле это действие не возвращается после вызова этого метода. Я пытался загрузить большой файл, и мне пришлось ждать, пока файл полностью загружен и обработан. Итак, что я должен сделать, чтобы это действие действительно выполнялось асинхронно?

Ответы [ 2 ]

0 голосов
/ 04 сентября 2018

Вызывающая сторона вашего проекта Web Api не имеет представления о деталях C #, о том, что означает Task или await. Это может быть C # или JS или даже PHP или человек, который набрал ваш URL в строке браузера.

Ваш Web Api по умолчанию (и должен!) Будет ждать завершения всей обработки, а затем подаст сигнал об успешном завершении. Обычно это делается с помощью кода состояния в качестве возвращаемого значения.

Теперь клиент , вызывающий вашего API, не должен застрять в ожидании этого. Но это программирование на стороне клиента. Вы действительно не можете ничего сделать в своем API, чтобы решить проблему клиента с этим.

В противном случае вы можете заставить свой API просто поместить файл в очередь обработки для последующей обработки другим программным обеспечением. Но для этого потребуется другая архитектура, потому что теперь вызывающий должен получать уведомления об успешном сбое (или общем результате), когда он больше не подключен к вашему API, поэтому вам понадобятся обратные вызовы.

0 голосов
/ 04 сентября 2018

У меня был этот код для обработки больших файлов (это было для загрузки большого файла CSV):

    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...
    }

Существуют настройки web.config для увеличения разрешенного времени загрузки файла, это может помочь: Как увеличить максимальный размер загружаемого файла в ASP.NET?

Если ваш запрос превышает максимально допустимое время ожидания, данные не будут возвращены вашему абоненту, как ожидалось!

Если вы хотите выполнить код «запустил и забыл» из C #, вы можете сделать это:

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();

Некоторые советы по асинхронности / ожиданию для Js: http://2ality.com/2016/10/async-function-tips.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...