繁体   English   中英

如何处理以 IAsyncEnumerable 作为返回类型的方法中的错误

[英]How to handle errors in method that has IAsyncEnumerable as return type

我有一个 API 端点:

[HttpGet("api/query")]
public async IAsyncEnumerable<dynamic> Query(string name)
{    
   await foreach(var item in _myService.CallSomethingReturningAsyncStream(name))
   {
       yield return item;
   }
}

我希望能够在 ArgumentException 的情况下返回类似“错误请求”的响应。

如果我尝试使用 try-catch 块,我会收到错误消息:

CS1626:无法在带有 catch 子句的 try 块主体中产生值

请注意,它是一个 API 端点方法,因此理想情况下错误处理应该在同一个方法中,而不需要制作额外的中间件。

你必须拆分方法。 提取进行异步处理的部分:

private async IAsyncEnumerable<dynamic> ProcessData(TypeOfYourData data)
{    
   await foreach(var item in data)
   {
       yield return item;
   }
}

然后在 API 方法中执行:

[HttpGet("api/query")]
public IActionResult Query(string name)
{    
   TypeOfYourData data;
   try {
       data = _myService.CallSomethingReturningAsyncStream(name);
   }
   catch (...) {
        // do what you need
        return BadRequest();
   }
   return Ok(ProcessData(data));
}

或者实际上你可以将整个事情移动到单独的方法中:

[HttpGet("api/query")]
public IActionResult Query(string name)
{           
   try {
       return Ok(TheMethodYouMovedYourCurrentCodeTo);
   }
   catch (...) {
        // do what you need
        return BadRequest();
   }
}

它当然只会捕获在实际异步枚举开始之前抛出的异常,但据我了解,这对您的用例来说很好。 在异步枚举开始后返回错误的请求是不可能的,因为响应已经被发送到客户端。

您可以安装System.Interactive.Async package,然后执行以下操作:

[HttpGet("api/query")]
public IAsyncEnumerable<dynamic> Query(string name)
{
    return AsyncEnumerableEx.Defer(() => _myService.CallSomethingReturningAsyncStream(name))
        .Catch<dynamic, Exception>(ex =>
            AsyncEnumerableEx.Return<dynamic>($"Bad request: {ex.Message}"));
}

Defer算子的签名:

// Returns an async-enumerable sequence that invokes the specified
// factory function whenever a new observer subscribes.
public static IAsyncEnumerable<TSource> Defer<TSource>(
    Func<IAsyncEnumerable<TSource>> factory)

Catch算子的签名:

// Continues an async-enumerable sequence that is terminated by
// an exception of the specified type with the async-enumerable sequence
// produced by the handler.
public static IAsyncEnumerable<TSource> Catch<TSource, TException>(
    this IAsyncEnumerable<TSource> source,
    Func<TException, IAsyncEnumerable<TSource>> handler);

Return操作员的签名:

// Returns an async-enumerable sequence that contains a single element.
public static IAsyncEnumerable<TValue> Return<TValue>(TValue value)

Defer可能看起来很肤浅,但在_myService.CallSomethingReturningAsyncStream同步抛出的情况下需要它。 如果此方法作为async迭代器实现,它永远不会同步抛出异常,因此您可以省略Defer

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM