无法在核心管道的中间件中实现 try-catch 的可调用捕获
Can't implement invokable catch of try-catch in middleware in Core pipeline
我已将自定义中间件添加到我的 Startup class(按照示例 here)。
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use((context, next) =>
{
try { return next(); }
catch (Exception exception) { return new Task(() => { }); }
});
app.UseCors("Welcome All");
app.UseMvc();
app.UseSwagger();
app.UseSwaggerUI(_ => _.SwaggerEndpoint("/swagger/v0.1/swagger.json", "Version 0.1"));
}
据我了解,在我的控制器方法中抛出异常应该在自定义中间件的 try-catch 中捕获。但 .NET Core 似乎与我的预期不符。通过断点我可以看到 return next() 被调用 但是 在控制器的方法抛出异常之后,异常是' t 被捕获,黄色标记一起跳过中间件并落在中间件的末尾花括号处。
我错过了什么?
如果它有任何意义或意义,我的目标是将异常处理从我的方法移到横切中间以简化代码(我不想应用过滤器,因为我以没有 MVC 的纯 WebApi 为目标)。所以控制器和方法看起来像这样。
[Route("api/test")]
public class TestController : Controller
{
public TestController(...) { ... }
...
[HttpPost]
public IActionResult CrashBoom([FromBody] Thing input)
{
if (input.isCrashworthy)
throw new Exception("Boom")
else
return Ok();
}
}
这里的问题是请求委托,中间件的可执行部分,运行 是异步的。如果你看一下 next
的类型,你会发现它实际上是一个 Func<Task>
,所以它是一个函数,return 是一个任务。或者换句话说:它是一个没有 return 值的异步函数。
这意味着为了能够捕获异常,您需要保持异步上下文。所以你的自定义中间件也应该异步执行。如果你这样做,你会注意到你可以捕获异常然后相应地响应它们,例如通过写出纯文本响应(作为示例):
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
// let’s log the exception
var logger = context.RequestServices.GetService<ILogger<Startup>>();
logger.LogWarning(ex, "Encountered an exception");
// write a response
context.Response.StatusCode = 500;
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Sorry, something went wrong!");
}
});
现在,如果在中间件管道中进一步引发异常,那么您的自定义管道将能够捕获它并做出响应。
我已将自定义中间件添加到我的 Startup class(按照示例 here)。
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use((context, next) =>
{
try { return next(); }
catch (Exception exception) { return new Task(() => { }); }
});
app.UseCors("Welcome All");
app.UseMvc();
app.UseSwagger();
app.UseSwaggerUI(_ => _.SwaggerEndpoint("/swagger/v0.1/swagger.json", "Version 0.1"));
}
据我了解,在我的控制器方法中抛出异常应该在自定义中间件的 try-catch 中捕获。但 .NET Core 似乎与我的预期不符。通过断点我可以看到 return next() 被调用 但是 在控制器的方法抛出异常之后,异常是' t 被捕获,黄色标记一起跳过中间件并落在中间件的末尾花括号处。
我错过了什么?
如果它有任何意义或意义,我的目标是将异常处理从我的方法移到横切中间以简化代码(我不想应用过滤器,因为我以没有 MVC 的纯 WebApi 为目标)。所以控制器和方法看起来像这样。
[Route("api/test")]
public class TestController : Controller
{
public TestController(...) { ... }
...
[HttpPost]
public IActionResult CrashBoom([FromBody] Thing input)
{
if (input.isCrashworthy)
throw new Exception("Boom")
else
return Ok();
}
}
这里的问题是请求委托,中间件的可执行部分,运行 是异步的。如果你看一下 next
的类型,你会发现它实际上是一个 Func<Task>
,所以它是一个函数,return 是一个任务。或者换句话说:它是一个没有 return 值的异步函数。
这意味着为了能够捕获异常,您需要保持异步上下文。所以你的自定义中间件也应该异步执行。如果你这样做,你会注意到你可以捕获异常然后相应地响应它们,例如通过写出纯文本响应(作为示例):
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
// let’s log the exception
var logger = context.RequestServices.GetService<ILogger<Startup>>();
logger.LogWarning(ex, "Encountered an exception");
// write a response
context.Response.StatusCode = 500;
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Sorry, something went wrong!");
}
});
现在,如果在中间件管道中进一步引发异常,那么您的自定义管道将能够捕获它并做出响应。