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;
}