I am looking for a way to return the details of any exception that occur when calling a method of my web API.
By default in production environment, error 500 "Internal Server Error" is the only information returned by the API.
It is a private API that is not published over the internet, and the caller application needs to get and store all details in case of exception.
The exception details could be JSON formatted in the HttpResponse content, allowing the caller to read the Message attribute, and the StackTraceString attribute of the exception (No HTTP page like UseDeveloperExceptionPage configuration).
Currently the default Startup Configure method is:
public class Startup
{
[...]
public void Configure(IApplicationBuilder app, IHostingEnvironment env, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory)
{
loggerFactory.AddNLog();
env.ConfigureNLog(Path.Combine(AppContext.BaseDirectory, "nlog.config"));
if ( env.IsDevelopment() )
app.UseDeveloperExceptionPage();
else
app.UseStatusCodePages();
app.UseMvc();
}
}
You could write a custom middleware, which intercepts all exceptions and returns them to the caller:
public class ExceptionHandler
{
private readonly RequestDelegate _next;
public ExceptionHandler(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var response = context.Response;
response.ContentType = "application/json";
response.StatusCode = (int)HttpStatusCode.InternalServerError;
await response.WriteAsync(JsonConvert.SerializeObject(new
{
// customize as you need
error = new
{
message = exception.Message,
exception = exception.GetType().Name
}
}));
}
}
and register it in your Startup Configure method:
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
app.UseMiddleware<ExceptionHandler>();
Alternatively to middleware, you can create ActionFilterAttribute and change IActionResult
Here is simple example attribuet that for all unhandled exceptions returns 400 Bad request with Exception method.
public class MyUnhandledExceptionFilter : ActionFilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext context)
{
context.Result = new BadRequestObjectResult(context.Exception.Message);
}
}
You then register it in startup's ConfigureServices method like this
services.AddMvc(options =>
{
options.Filters.Add(typeof(MyUnhandledExceptionFilter));
})
This only catches exceptions that reached MVC, which in most cases is what you need