【问题标题】:How to make ASP.NET Core Web API action execute asynchronously?如何使 ASP.NET Core Web API 操作异步执行?
【发布时间】:2019-02-09 05:22:31
【问题描述】:

我的 ASP.NET Core Web API 的控制器中有一个动作,用于上传和处理文件。文件小没关系,但文件大了怎么办?我希望这个动作异步执行,所以我将方法定义为async,它的返回值只是Task可以等待,并在await Task.Run(() => ...)块中插入连续操作,使动作也async并调用这个方法带有await关键字,但实际上调用该方法后该动作并没有返回。我试图上传大文件,并且不得不等到文件完全上传和处理。那么,我应该怎么做才能让这个动作真正异步执行呢?

【问题讨论】:

  • 一个方法如果遇到await 将不会立即返回 - await 是该方法执行的暂停点,直到awaited Task 完成。
  • 你应该使用异步任务 请访问stackoverflow.com/questions/41953102/…
  • 那么,它是在不同的任务中执行的,但我还需要等待它吗?如何不等待就让这个任务成为后台?
  • 正如我在问题描述中提到的,我已经分别将操作设为异步,我还将其返回值设为 Task<IActionResult>

标签: c# asynchronous asp.net-core-webapi


【解决方案1】:

Web Api 项目的调用方不知道 C# 细节,不知道 Task 是什么或 await 是什么意思。它可能是 C# 或 JS 甚至是 PHP,或者是在浏览器栏中键入您的 URL 的人。

默认情况下(并且应该!)您的 Web Api 将等待整个处理完成,然后发出成功的信号。这通常通过状态码作为返回值来完成。

现在客户端调用您的 API 不必等待。但那是客户端编程。你不能在你的 API 中做任何事情来解决客户的问题。

否则,您可以让您的 API 将文件放入处理队列中,以便稍后由不同的软件处理。但这需要另一种架构,因为现在调用者需要在不再连接到您的 API 时收到失败成功(或一般结果)的通知,因此您需要回调。

【讨论】:

  • 谢谢!您能否推荐一些资源来了解 ASP.NET Core 中的处理队列?
  • 对于 ASP.NET Core 队列和处理没有什么特别的。您的 API 将请求写入队列(您认为合适的任何类型...文件、数据库、消息队列、biztalk),然后另一个进程在该队列上运行并逐个处理项目。最后,它需要一个通道来通知原始调用者。没有单一的技术,但如果你用谷歌搜索“服务总线”,你可能会发现一些有趣的话题。
  • 谢谢!这真的很有帮助。
【解决方案2】:

我有这段代码用于处理大文件(这是用于上传大型 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 设置可以增加文件上传的允许时间,这可能会有所帮助:How to increase the max upload file size in 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 的 async/await 技巧:http://2ality.com/2016/10/async-function-tips.html

【讨论】:

  • 我有几乎相同的代码,但它仍然不是异步的。问题是我必须等待我的方法完成,我想将上传的文件发送到方法中,然后从操作返回OkActionResult。
  • 如果您在浏览器中通过脚本执行调用,您是否看到它在几分钟后超时?我会尝试 web.config 设置,看看是否有帮助:)
  • 不,浏览器中没有任何内容。你看,代码是正确的并且执行正确,我只是希望用户不要等待它完全执行。
猜你喜欢
  • 2013-11-23
  • 1970-01-01
  • 1970-01-01
  • 2011-03-20
  • 2021-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-01
相关资源
最近更新 更多