Как проверить с помощью фильтров, отправляет ли клиент действительный JSON? - PullRequest
0 голосов
/ 26 января 2020

У меня есть следующий запрос:

enter image description here

Как вы можете видеть, это недействительно JSON. Даже это не JSON. Это просто случайный набор букв. Я хотел бы проверить, что клиент не может передать тело, как на экране раньше, в моем веб-API. Если это произойдет, я хотел бы отправить что-то вроде:

{
    "status": "error",
    "description": "Invalid JSON"
}

Итак, у меня есть следующий фильтр:

public class MyValidateJson : ActionFilterAttribute
    {
        public override async void OnActionExecuting(ActionExecutingContext context)
        {
            // check if json is valid
            using StreamReader reader = new StreamReader(context.HttpContext.Request.Body, Encoding.UTF8);
            var body = await reader.ReadToEndAsync();

            try
            {
                JToken.Parse(body);
            }
            catch (JsonReaderException ex)
            {
                context.Result = new BadRequestObjectResult(new
                {
                    status = "error",
                    description = "Invalid JSON input"
                });

                base.OnActionExecuting(context);
            }

Но я не могу прочитать тело. У меня всегда есть пустая строка. И в результате у меня всегда неверный JSON. Как я могу улучшить свой фильтр?

Обновление

Может быть, мое объяснение проблемы не ясно, я постараюсь это исправить. Итак, я хотел бы избежать этой ситуации:

enter image description here

Как вы можете видеть {"":["Error parsing boolean value. Path '', line 1, position 1."]} - это ... что это для моего клиента? Для клиента это должно быть что-то вроде:

{
   "status": "error",
   "description": "Your JSON is invalid, we are sorry ((("
}

, но не {"":["Error parsing boolean value. Path '', line 1, position 1."]}

У меня есть следующий контроллер:

   [Route("/api/v1.0/startup")]
        [HttpPost]
        public async Task<IActionResult> Update([FromBody] CustomerChangeViewModel viewModel)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
    ...

И просмотр модели тоже:

 public class CustomerChangeViewModel
    {
        [JsonProperty("idfa")]
        [Required(ErrorMessage = "Required idfa")]
        public string Idfa { get; set; }

        [JsonProperty("idfv")]
        [Required(ErrorMessage = "Required idfv")]
        public string Idfv { get; set; }

        [Required(ErrorMessage = "Required app_build_number")]
        [JsonProperty("app_build_number")]
        public string AppBuildNumber { get; set; }

        [JsonProperty("app_version")]
        [Required(ErrorMessage = "Required app_version")]
        public string AppVersion { get; set; }
    ...

Как я могу получить это поведение? Я имею в виду с хорошим ответом (не текст исключения).

Ответы [ 2 ]

0 голосов
/ 27 января 2020

Проблема в том, что вы не получаете тело запроса в Action Filter, поэтому в фильтре он неправильно проверяет Json анализ и возвращает пользовательскую ошибку. Вы можете попробовать следующие коды, чтобы получить тело запроса в OnActionExecuting:

var bodyStr = "";
var req = context.HttpContext.Request;           
req.EnableRewind();
req.Body.Position = 0;
using (var stream = new StreamReader(req.Body))
{
   bodyStr = stream.ReadToEnd();
}
0 голосов
/ 26 января 2020

Вы можете использовать DTO (Data Transfer Object) класс для получения и проверки вашего желаемого JSON с помощью System.ComponentModel.DataAnnotations. В моем случае это для регистра учетной записи:

    public class AccountRegisterDTO
    {
        [Required] // This property is obligatory, it MUST exist in JSON
        [MinLength(6, ErrorMessage = "Username must be at least 6 characters long")] // Must be minimum 6 characters long
        [RegularExpression(@"^\d*[a-zA-Z][a-zA-Z\d]*$", ErrorMessage = "Username can contain only letters and numbers")] // Must Match the RegEx
        public string Username { get; set; }

        [Required]
        [MinLength(8, ErrorMessage = "Password must be at least 8 characters long")]
        [RegularExpression(@"^(?=.*[A-Z])(?=.*[a-z])(?=.*[\d])((?=.*[^\w\s])|(?=.*[ ])).*$", ErrorMessage = "Password don't meet passwords policy")]
        public string Password { get; set; }

        [Required]
        [EmailAddress(ErrorMessage = "Email address is not valid")] // Automatically validate if e-mail address is correct
        public string EmailAddress { get; set; }
    }

Использование очень просто, это выглядит так:

        [HttpPost("Register")]
        public async Task<IActionResult> Register([FromBody] AccountRegisterDTO registerAccount)
        {
            // Code will not even reach this point if JSON is not valid according to DataAnnotations Attributes
        }

Для переданных аргументов:

enter image description here

Возвращенные ошибки выглядят так:

enter image description here

...