![](/img/trans.png)
[英]How to intercept an async method with IAsyncEnumerable<T> as return type in .netcore 3.0
[英]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.