I've added a custom middleware to my Startup class (following the example 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"));
}
It was my understanding that throwing an exception in my method in a controller should be caught in try-catch of the custom middleware. But .NET Core seems to diagree with my expectations. By the breakpoints I can see that return next() is invoked but after the controller's method throws an exception, the exception isn't caught and the yellow marker jumps past the middleware alltoghether and lands at the end curly brace of it.
What am I missing?
If it's of any significance or interest, my aim is to move out the exception handling from my methods to the cross-cut middy in orde to simplify the code (and I want not to apply filters, since I'm targetting pure WebApi without MVC). So the controller and the method look something like this.
[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();
}
}
The problem here is that request delegates, the executable parts of a middleware, run asynchronously. If you look at the type of next
you can see that it is actually a Func<Task>
, so it’s a function that returns a task. Or in other words: It’s an asynchronous function without a return value.
That means that in order to be able to catch exceptions, you need to keep the asynchronous context. So your custom middleware should execute asynchronously as well. If you do that, you will notice that you can catch exceptions and then respond to them accordingly, for example by writing out a plain text response (as an example):
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!");
}
});
Now, if an exception is raised further down the middleware pipeline, then your custom pipeline will be able to catch it and respond to it.