【问题标题】:Asynchronous function returns async metadata (including result) instead of just result异步函数返回异步元数据(包括结果)而不仅仅是结果
【发布时间】:2020-11-05 01:21:27
【问题描述】:

我正在使用 .NET Core 3.1 编写 API。此 API 有一个名为 GetSomeProperty() 的异步函数,我在端点(称为 Get)中使用它。

当接收到来自该端点的响应时,results 属性被“下移”一层,并包装在来自异步方法的元数据中,如下所示:

"results": [
    {
        "result": {//actual result here}
        "id": 1,
        "status": 5,
        "isCanceled": false,
        "isCompleted": true,
        "creationOptions": 0,
        "isFaulted": false
    },
    {
        "result": {//actual result here}
        "id": 2,
        "status": 5,
        "isCanceled": false,
        "isCompleted": true,
        "creationOptions": 0,
        "isFaulted": false
    }
]

我不希望将这些结果包装在这个“异步”包装器中。

在保持方法异步的同时,如何返回任务结果,而不是包含任务结果的对象?

我没有使用.Result的原因有两个:

  1. 使用.Result 被认为是不好的做法,因为如果任务尚未完成,它可能会导致锁定。
  2. 我不知道该放在哪里。据我所知,它似乎不适合任何地方。

这是代码(请记住,为了示例目的,这已被大大稀释和简化):

[HttpGet]
public async Task<object> Get(string someParameter)
{   
    //Do stuff

    var things = BuildACollectionOfItems();
    var results = things.Select(x => x.IrrelevantThing).OrderBy(x => x.SomethingIrrelevant).Select(async x =>
    {
        return new
        {
            x.Id,
            SomeProperty = await GetSomeProperty(x.Id)
        };
    }).ToArray();

    return new
    {
        Results = ((IEnumerable<object>) results),
        SomeIrrelevantThing = someIrrelevantThing
    };
}

private async Task<bool> GetSomeProperty(int id)
{
    var somethingFromAServer = (await _thingProvider.GetThing()).TheProperty;

    //Do stuff here

    var thing = _context.Stuff.FirstOrDefault(x => x.Thing == somethingFromAServer);

    //Do some more stuff

    return thing.Stuff;
}

【问题讨论】:

  • 附注:为您的async 方法考虑一个后缀Asyncasync Task&lt;bool&gt; GetSomePropertyAsync(int id)
  • 部分猜测,但things.Select() 可以等待吗?例如:var results = await things.Select(...) 从结构上看,Get() 本身并没有在等待任何东西,结果是得到一个任务列表。
  • 某处您未能解开任务 - 通常是缺少await。检查的好地方是你强制变量为object的地方——它可以引用任何东西,包括Task&lt;object&gt;——并检查为你的var变量推断出的实际类型。
  • @dymanoid 好点,从现在开始我会记住这一点。
  • @Jessica:在这种情况下,.Select()IEnumerable 上的标准 LINQ 方法吗?如果是这样,那么这看起来很有希望:stackoverflow.com/questions/14938467/… 可能需要额外的几个步骤,但我们的想法是在返回整个结果之前等待结果中的所有任务。我现在无法对其进行测试,但它可能就像在该方法结束时将您的分配更改为 Results = Task.WhenAll(results) 一样简单

标签: c# json asynchronous .net-core async-await


【解决方案1】:

您的Select 返回IEnumerable&lt;Task&gt;(因为它传递了async 函数);您可以使用Task.WhenAll 等待它们全部完成,然后打开结果:

[HttpGet]
public async Task<object> Get(string someParameter)
{   
    //Do stuff

    var things = BuildACollectionOfItems();
    var results = await Task.WhenAll(things
        .Select(x => x.IrrelevantThing)
        .OrderBy(x => x.SomethingIrrelevant)
        .Select(async x => new
        {
            x.Id,
            SomeProperty = await GetSomeProperty(x.Id)
        }));

    return new
    {
        Results = ((IEnumerable<object>) results),
        SomeIrrelevantThing = someIrrelevantThing
    };
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 2019-09-30
    • 2014-10-02
    • 2020-12-24
    • 2016-03-11
    • 1970-01-01
    • 2022-12-22
    相关资源
    最近更新 更多