【发布时间】: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的原因有两个:
- 使用
.Result被认为是不好的做法,因为如果任务尚未完成,它可能会导致锁定。 - 我不知道该放在哪里。据我所知,它似乎不适合任何地方。
这是代码(请记住,为了示例目的,这已被大大稀释和简化):
[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方法考虑一个后缀Async:async Task<bool> GetSomePropertyAsync(int id)。 -
部分猜测,但
things.Select()可以等待吗?例如:var results = await things.Select(...)从结构上看,Get()本身并没有在等待任何东西,结果是得到一个任务列表。 -
某处您未能解开任务 - 通常是缺少
await。检查的好地方是你强制变量为object的地方——它可以引用任何东西,包括Task<object>——并检查为你的var变量推断出的实际类型。 -
@dymanoid 好点,从现在开始我会记住这一点。
-
@Jessica:在这种情况下,
.Select()是IEnumerable上的标准 LINQ 方法吗?如果是这样,那么这看起来很有希望:stackoverflow.com/questions/14938467/… 可能需要额外的几个步骤,但我们的想法是在返回整个结果之前等待结果中的所有任务。我现在无法对其进行测试,但它可能就像在该方法结束时将您的分配更改为Results = Task.WhenAll(results)一样简单
标签: c# json asynchronous .net-core async-await