异步函数返回异步元数据(包括结果),而不只是结果

时间:2020-07-15 13:59:06

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

我正在使用.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;
}

1 个答案:

答案 0 :(得分:5)

您的Select返回IEnumerable<Task>(因为它被传递了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
    };
}