这是由 JsonInputFormatter ReadRequestBodyAsync 方法的行为引起的。
我遇到了一些使用自定义错误消息的选项,但没有一个是优雅的。
选项 1:覆盖 ReadRequestBody 以添加已修复的错误消息。
public class CustomJsonInputFormatter : JsonInputFormatter
{
private readonly IArrayPool<char> charPool;
private readonly MvcOptions options;
public CustomJsonInputFormatter(ILogger logger, JsonSerializerSettings serializerSettings, ArrayPool<char> charPool, ObjectPoolProvider objectPoolProvider, MvcOptions options, MvcJsonOptions jsonOptions)
: base(logger, serializerSettings, charPool, objectPoolProvider, options, jsonOptions)
{
this.charPool = new JsonArrayPool<char>(charPool);
this.options = options;
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(
InputFormatterContext context,
Encoding encoding)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (encoding == null)
{
throw new ArgumentNullException(nameof(encoding));
}
var request = context.HttpContext.Request;
var suppressInputFormatterBuffering = options?.SuppressInputFormatterBuffering ?? false;
if (!request.Body.CanSeek && !suppressInputFormatterBuffering)
{
// JSON.Net does synchronous reads. In order to avoid blocking on the stream, we asynchronously
// read everything into a buffer, and then seek back to the beginning.
request.EnableBuffering();
Debug.Assert(request.Body.CanSeek);
await request.Body.DrainAsync(CancellationToken.None);
request.Body.Seek(0L, SeekOrigin.Begin);
}
using (var streamReader = context.ReaderFactory(request.Body, encoding))
{
using (var jsonReader = new JsonTextReader(streamReader))
{
jsonReader.ArrayPool = charPool;
jsonReader.CloseInput = false;
var successful = true;
Exception exception = null;
void ErrorHandler(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs eventArgs)
{
successful = false;
var path = eventArgs.ErrorContext.Path;
var key = ModelNames.CreatePropertyModelName(context.ModelName, path);
context.ModelState.TryAddModelError(key, $"Invalid value specified for {path}");
eventArgs.ErrorContext.Handled = true;
}
var type = context.ModelType;
var jsonSerializer = CreateJsonSerializer();
jsonSerializer.Error += ErrorHandler;
object model;
try
{
model = jsonSerializer.Deserialize(jsonReader, type);
}
finally
{
// Clean up the error handler since CreateJsonSerializer() pools instances.
jsonSerializer.Error -= ErrorHandler;
ReleaseJsonSerializer(jsonSerializer);
}
if (successful)
{
if (model == null && !context.TreatEmptyInputAsDefaultValue)
{
// Some nonempty inputs might deserialize as null, for example whitespace,
// or the JSON-encoded value "null". The upstream BodyModelBinder needs to
// be notified that we don't regard this as a real input so it can register
// a model binding error.
return InputFormatterResult.NoValue();
}
else
{
return InputFormatterResult.Success(model);
}
}
if (!(exception is JsonException || exception is OverflowException))
{
var exceptionDispatchInfo = ExceptionDispatchInfo.Capture(exception);
exceptionDispatchInfo.Throw();
}
return InputFormatterResult.Failure();
}
}
}
}
选项 2:在InvalidModelStateResponseFactory 中执行模式匹配并替换错误
解析值时遇到意外字符:T. Path 'parent.booleanChild', line 0, position 0
选项 3:将 AllowInputFormatterExceptionMessages 设置为 false,并在 InvalidModelStateResponseFactory 中假设任何空白消息都是由于序列化错误造成的。
我没有将此标记为 答案,因为我相信其他人会有更好的主意。
我提出了GitHub issue,它提出了我认为可能的解决方案。
我发现的其他 SO 问题:
ASP.NET Core handling JSON deserialization problems
Overriding ModelBindingMessageProvider error messages