我在 StackOverflow 上遇到过很多关于这个错误的问题,但没有一个能达到我的目的。
我想做的是将下面的错误消息数组翻译成更易读的内容
{
"parent.booleanChild": [
"Unexpected character encountered while parsing value: T. Path 'parent.booleanChild', line 0, position 0",
"Unexpected character encountered while parsing value: r. Path 'parent.booleanChild', line 0, position 0"
]
}
期望的结果
{
"parent.booleanChild": [
"Value 'True' is not valid, only 'true', 'false' and 'null' are allowed."
]
}
示例请求
{
"parent": {
"booleanChild": True
}
}
我已尝试实现自定义 JsonConverter
,但发现在执行转换器之前引发了 JsonReaderException
。
有没有人实现了类似的东西,使他们能够在不实现自定义 IInputFormatter
的情况下生成更有意义和可读的错误消息?
最佳答案
这是由 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
中执行模式匹配并替换错误
Unexpected character encountered while parsing value: T. Path 'parent.booleanChild', line 0, position 0
选项 3:设置 AllowInputFormatterExceptionMessages
为假并在 InvalidModelStateResponseFactory
中做出假设任何空白消息都是由于序列化错误造成的。
我不会将此标记为答案,因为我相信其他人会有更好的主意。
我提出了一个GitHub issue它提出了我认为可能是解决方案的方法。
我发现的其他SO问题:
关于c# - JsonReaderException - 解析值时遇到意外字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59877835/