You can use an action filter to capture any model binding error (including deserialization errors). You can pull the error from the ActionExecutingContext.
EDIT: To use this approach, You need to suppress the model state invalid filter because by default web api will automatically return a 400 if there is a binding error. https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.apibehavioroptions.suppressmodelstateinvalidfilter#microsoft-aspnetcore-mvc-apibehavioroptions-suppressmodelstateinvalidfilter
public class LogModelBindingErrorFilter : IActionFilter
{
private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
public void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
var messages = context.ModelState.Values
.SelectMany(x => x.Errors)
.Where(x => x.Exception is JsonException)
.Select(x => x.ErrorMessage);
_logger.Log(LogLevel.Error, string.Join(", ", messages));
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}