C# 返回IAsyncEnumerable<;T>;在Asp.Net核心控制器中找不到
对于返回C# 返回IAsyncEnumerable<;T>;在Asp.Net核心控制器中找不到,c#,asp.net-core,async-await,asp.net-core-mvc,C#,Asp.net Core,Async Await,Asp.net Core Mvc,对于返回IAsyncEnumerable和NotFoundResult但仍以异步方式处理的控制器操作,正确的签名是什么 我使用了此签名,但它没有编译,因为IAsyncEnumerable不可等待: [HttpGet] public async Task<IActionResult> GetAll(Guid id) { try { return Ok(await repository.GetAll(id)); // GetAll() returns an
IAsyncEnumerable
和NotFoundResult
但仍以异步方式处理的控制器操作,正确的签名是什么
我使用了此签名,但它没有编译,因为
IAsyncEnumerable
不可等待:
[HttpGet]
public async Task<IActionResult> GetAll(Guid id)
{
try
{
return Ok(await repository.GetAll(id)); // GetAll() returns an IAsyncEnumerable
}
catch (NotFoundException e)
{
return NotFound(e.Message);
}
}
我尝试像这样使用await-foreach
循环,但显然也无法编译:
[HttpGet]
public async IAsyncEnumerable<MyObject> GetAll(Guid id)
{
IAsyncEnumerable<MyObject> objects;
try
{
objects = repository.GetAll(id); // GetAll() returns an IAsyncEnumerable
}
catch (NotFoundException e)
{
return NotFound(e.Message);
}
await foreach (var obj in objects)
{
yield return obj;
}
}
[HttpGet]
公共异步IAsyncEnumerable GetAll(Guid id)
{
IAsynceneumber对象;
尝试
{
objects=repository.GetAll(id);//GetAll()返回一个IAsyncEnumerable
}
捕获(未发现异常)
{
返回未找到(e.Message);
}
等待foreach(对象中的var obj)
{
收益率目标;
}
}
选项2可以将IAsyncEnumerable
的实现传递到Ok
调用中。ASP.NET核心管道负责枚举,并且从3.0开始就支持IAsyncEnumerable
以下是问题的答案,根据上下文重复:
对的调用将创建的实例,该实例将继承。传递到Ok
的值属于object
类型,保存在ObjectResult
的属性中。ASP.NET核心MVC使用,其中该命令是IActionResult
的实现,并使用的实现执行
对于ObjectResult
,用于将ObjectResult
转换为HTTP响应。它是ObjectResultExecutor.ExecuteAsync
的一个属性,它是IAsyncEnumerable
-感知的:
如代码所示,将检查
值
属性以查看它是否实现了IAsyncEnumerable
(详细信息隐藏在对的调用中)。如果是,则调用,它执行枚举,然后将枚举结果传递到ExecuteAsyncore
:
使用
wait-foreach
将IAsyncEnumerable
枚举到列表中,根据定义,它几乎不会阻止请求线程。正如Panagiotis Kanavos在对OP的评论中所指出的,在将响应发送回客户端之前,将完整执行此枚举。您将返回多个MyObject
项,这些项具有相同的id
?通常情况下,对于返回IEnumerable
的内容,您不会发送NotFound
——它将是空的——或者您将返回带有请求的id
/NotFound
的单个项目iasyncnumerable
正在等待。使用wait-foreach(ThatMethodAsync()中的var项){…}
。如果要返回IAsyncEnumerable
,只需返回结果,例如返回对象
。但这不会将HTTP操作转换为流式gRPC或信号器方法。中间件仍将使用数据,并向clientOption 2发送一个HTTP响应。ASP.NET核心管道负责枚举,并且从3.0.0开始就支持IAsyncEnumerable。我知道这里没有返回404,但这只是一个人为的例子。实际代码完全不同@KirkLarkin很抱歉成为一个害虫,但你100%确定这不会造成任何阻塞吗?如果是,那么选择2是显而易见的解决方案。
[HttpGet]
public async IAsyncEnumerable<MyObject> GetAll(Guid id)
{
IAsyncEnumerable<MyObject> objects;
try
{
objects = repository.GetAll(id); // GetAll() returns an IAsyncEnumerable
}
catch (NotFoundException e)
{
return NotFound(e.Message);
}
await foreach (var obj in objects)
{
yield return obj;
}
}
return Ok(repository.GetAll(id)); // GetAll() returns an IAsyncEnumerable
public virtual Task ExecuteAsync(ActionContext context, ObjectResult result)
{
// ...
var value = result.Value;
if (value != null && _asyncEnumerableReaderFactory.TryGetReader(value.GetType(), out var reader))
{
return ExecuteAsyncEnumerable(context, result, value, reader);
}
return ExecuteAsyncCore(context, result, objectType, value);
}
private async Task ExecuteAsyncEnumerable(ActionContext context, ObjectResult result, object asyncEnumerable, Func<object, Task<ICollection>> reader)
{
Log.BufferingAsyncEnumerable(Logger, asyncEnumerable);
var enumerated = await reader(asyncEnumerable);
await ExecuteAsyncCore(context, result, enumerated.GetType(), enumerated);
}
private async Task<ICollection> ReadInternal<T>(object value)
{
var asyncEnumerable = (IAsyncEnumerable<T>)value;
var result = new List<T>();
var count = 0;
await foreach (var item in asyncEnumerable)
{
if (count++ >= _mvcOptions.MaxIAsyncEnumerableBufferLimit)
{
throw new InvalidOperationException(Resources.FormatObjectResultExecutor_MaxEnumerationExceeded(
nameof(AsyncEnumerableReader),
value.GetType()));
}
result.Add(item);
}
return result;
}