【问题标题】:What could cause async lambda to return unwanted data about the operation in Ok IActionResult?什么可能导致异步 lambda 返回有关 Ok IActionResult 中操作的不需要的数据?
【发布时间】:2021-08-16 17:43:19
【问题描述】:

我尝试在我的 lambda 函数中使用 await 来异步完成操作,以简化我遗漏了不必要的操作(where 子句等)的问题,并将异步方法命名为 Services.CustomerAmountService.QueryDbAndReturnResult

该函数接受一个 double(数量之和)并执行许多任务,但最重要的是一个异步调用(firstAsync,这使得函数可等待)

[HttpGet]
public async Task<IActionResult> GetCustomersAndAmount()
{
    try
    {
        return Ok((await _orderRepository.CustomMadeQueryThatReturnsIQueryable()
            .Select(x => new
            {
                CustomerId = x.CustomerId,
                CustomerName = x.Customer.Name
                Amount = x.Amount
            })
            .ToListAsync())
            .GroupBy(x => x.CustomerId )
            // this "async x" causes the unwanted result in my Ok() IActionResult
            .Select( async x => new
            {
                CustomerName = x.First().CustomerName,
                SumAmount = await Services.CustomerAmountService.QueryDbAndReturnResult(x.Sum(x => x.Amount)) 
            })
        ));
    }
    catch (Exception ex)
    {
        return BadRequest(ex.Message);
    }
}

结果如下:

{"1":[{"result":{"customerName":"VeryNiceCustomer","amount":1.0},"id":1269,"exception":null,"status":5,"isCanceled":false,"isCompleted":true,"isCompletedSuccessfully":true,"creationOptions":0,"asyncState":null,"isFaulted":false}]}

但是想要的结果和没有“async x”和异步函数的结果(所以只返回'1'并且根本不做进一步的操作)看起来像这样:

{"1":[{"customerName":"VeryNiceCustomer","amount":1}]}

我想知道我可以更改什么以始终获得第二个结果,而不用担心返回有关操作的不必要数据?它似乎正在返回一个结果,但我只对结果的结果感兴趣(函数返回什么,而不是异步结果)

【问题讨论】:

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


    【解决方案1】:

    async lambda 被转换为Func&lt;T, Task&lt;T&gt;&gt;,因此您的返回实际上是IEnumerable&lt;Task&lt;GeneratedAnonymousType&gt;&gt; 类型。您可以使用Task.WhenAll 来转换结果:

    var resultTasks = (await _orderRepository.CustomMadeQueryThatReturnsIQueryable()
        .Select(x => new
        {
            CustomerId = x.CustomerId,
            CustomerName = x.Customer.Name
            Amount = x.Amount
        })
        .ToListAsync())
        .GroupBy(x => x.CustomerId )
        .Select( async x => new
        {
            CustomerName = x.First().CustomerName,
            SumAmount = await Services.CustomerAmountService.QueryDbAndReturnResult(x.Sum(x => x.Amount)) 
        }));
    
    return Ok(await Task.WhenAll(resultTasks));
    

    但总的来说,我建议修改整个方法 - 通常进行并行处理是一种气味。编写一个可以在一个查询中获取所有需要的数据的方法应该会更好。

    【讨论】:

    • 我绝不会建议在实体框架中使用WhenAll
    • 尊敬的大师,我了解您对问题的解决方案,但问题是返回类型仍然不是“IEnumerable>”,因此是“Task.WhenAll(resultTasks)”向我打招呼一个错误:(
    • @SvyatoslavDanyliv,你有其他选择吗? :-)
    • @PurpleTurtle 实际的错误文本是什么?
    • @SvyatoslavDanyliv 不确定 Services.CustomerAmountService.QueryDbAndReturnResult 是否使用 EF。
    【解决方案2】:

    您不能在 LINQ 方法中使用异步。您必须通过 foreach 枚举结果并进行 await 调用。 示意图:

    foreach (var x in items)
       SumAmount = await Services.CustomerAmountService.QueryDbAndReturnResult(x.Sum(x => x.Amount))
    

    但是,我认为,您的查询并不是最佳的:

    var query = _orderRepository.CustomMadeQueryThatReturnsIQueryable()
       .GroupBy(x => new
        {
            CustomerId = x.CustomerId,
            CustomerName = x.Customer.Name
        })
       .Select(g => new 
        {
             CustomerName = g.Key.CustomerName,
             SumAmount = g.Sum(x => x.Amount)
        });
    
    return return Ok(await query.ToListAsync());
    

    【讨论】:

      猜你喜欢
      • 2019-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-26
      • 1970-01-01
      • 2017-03-21
      • 1970-01-01
      • 2018-06-03
      相关资源
      最近更新 更多