Я достиг чего-то похожего на то, на что, я полагаю, вы ссылаетесь в своем вопросе, хотя это все еще довольно странно. И, вероятно, очень ненадежный.
Я, честно говоря, не могу поверить, что это не поддерживается (есть много причин, в которых я нуждаюсь, включая безопасность и ограничение сложности кодовой базы) - это особенно озадачивает, как новый System.Text.Json.Serialization
еще не поддерживает многие функции, которые предлагает Newtonsoft Json.
Моя попытка повторяет что-то похожее на вашу Option 2
, но не соответствует строковому шаблону. он полагается на то, что вы сможете извлечь подходящее сообщение из исключения, которое было сгенерировано во время привязки (и действительно, существующее исключение не будет работать, если сообщения не генерируются из исключений.)
Я сделал это в Asp. Net Core 3, хотя вы, вероятно, могли бы сделать нечто подобное в 2.2. Я решил не переопределять JsonInputFormatter, потому что я обнаружил, что для этого потребуется также переопределить большую часть соединения.
В моем случае все ошибки проверки генерируются указанным базовым классом исключений c. у которого достаточно контекста, чтобы определить, какой тип ответа должен быть предоставлен пользователю. Исключение будет помещено в исключение JsonSerializationException и отклонено JsonInputFormatter, поскольку оно считает, что это исключение времени выполнения. Однако, как вы указали, событие Error
в JsonSerializerSettings позволяет нам получить доступ к этому исключению.
Я сохраняю исключение и путь, предоставленный Json. Net, в хранилище, ограниченное запросом, в моем PO C case Я передаю ссылку IServiceProvider, полученную через набор сервисов, использованный при запуске. Таким образом, мы можем получить ссылку на оригинальный HttpContext, который затем может быть выбран InvalidModelStateResponseFactory.
Мой код запуска выглядит следующим образом: -
services
.AddControllers()
.ConfigureApiBehaviorOptions(options => options.InvalidModelStateResponseFactory = HandleTypedErrors)
.AddNewtonsoftJson(options => options.ApplySerializationErrorRecording(services));
}
private static IActionResult HandleTypedErrors(ActionContext actionContext)
{
if (actionContext.ModelState.IsValid)
{
return null;
}
var errors = actionContext.ModelState
.Select(modelError => new
{
State = modelError,
Exception = actionContext.HttpContext.RetrieveSerializationException<ErrorException>(modelError.Key)
})
.Where(state => state.Exception != null)
.Select(modelError => new
{
ErrorField = modelError.State.Key,
ErrorCode = modelError.Exception.ErrorCode,
ErrorDescription = modelError.Exception.Message
})
.ToList();
return errors.Any() ? new BadRequestObjectResult(errors.ToList()) : null;
}
Запись ошибок применения выглядит примерно так: -
public static MvcNewtonsoftJsonOptions ApplySerializationErrorRecording(this MvcNewtonsoftJsonOptions options, IServiceCollection services)
{
options.SerializerSettings.Error += (sender, args) =>
{
var provider = services.BuildServiceProvider();
var context = provider.GetRequiredService<IHttpContextAccessor>().HttpContext;
if (context == null || !(args.ErrorContext.Error is JsonException) ||
!(args.ErrorContext.Error.InnerException is ErrorException ex))
return;
var errors = context.Items["Error"] as Dictionary<string, ErrorException> ??
new Dictionary<string, ErrorException>();
errors.Add(args.ErrorContext.Path, ex);
context.Items["Error"] = errors;
};
return options;
}