Запрос jQuery JSON POST на ASP.NET Контроллер MVC не достигает конечной точки, но ручное использование маршрута работает корректно

#javascript #jquery #asp.net #asp.net-mvc

#javascript #jquery #asp.net #asp.net-mvc

Вопрос:

У меня есть ASP.NET приложение, состоящее из интерфейса, содержащего форму, данные которой я хочу передать в свой серверный сервер C #. Для этого я использую post-запрос jQuery для сериализации данных формы и отправки их контроллеру с использованием JSON. Ниже приведен мой код Javascript, который вызывает маршрут контроллера;

 $(".data-submit").on("click",
        function(event) {
            var formArray = $("#amend-form").serializeArray();
            var json = JSON.stringify(formArray);

            $.post(windowLocationOrigin()  
                "/Instruction/AmendData", 
                json, 
                function (data) {
                    alert("api endpoint called");
                });

        });
  

И вот вызывается конечная точка контроллера

         [Route("[controller]/AmendData")]
        public IActionResult AmendPortingData([FromBody] string json)
        {
            return Ok(json);
        }
  

Когда я отправляю эту форму через свой интерфейс, вызывается событие onClick JS и отправляется запрос post, однако конечная точка контроллера никогда не достигается. У меня есть точка останова в return Ok(json) строке, которая никогда не запускается после отправки формы.

Если я проверяю инструменты разработчика, я получаю ошибку 500 с сообщением: POST https://localhost:44358/Instruction/AmendData 500

Однако, если я затем отправлю запрос на этот URL, https://localhost:44358/Instruction/AmendData?json=123 конечная точка будет достигнута правильно, и я смогу увидеть значение 123 в моем отладчике.

Однако я хочу иметь возможность отправлять свои данные через тело запроса post, а не через URL, поскольку отправляемая форма большая и содержит слишком много данных для отправки через GET.

Я попытался добавить [HttpPost] атрибут к конечной точке контроллера, но это приводит к точно такому же поведению, за исключением того, что это не позволяет получить URL для работы.

Комментарии:

1. Попробуйте изменить на: var json = { json: JSON.stringify(formArray) };

2. @freedomn-m Это устранило мою проблему, спасибо! Не могли бы вы объяснить, почему невыполнение этого было причиной проблемы? Я хотел бы точно знать, почему это вызвало проблему.

Ответ №1:

Действие вашего контроллера:

 public IActionResult AmendPortingData(string json)
  

ожидается параметр с именем json .

Когда вы вызываете это с:

  $.ajax({ url: url, data: "string" });
  

передаваемые данные не имеют имени параметра, поэтому связующее устройство модели по умолчанию не может определить, какую часть данных применить к этому параметру.

Это работает с:

 http://url?json=string
  

поскольку вы указываете имя параметра ?json= , если вы вызвали свое действие с

 http://url/string
  

тогда он снова не распознает «string» как относящийся к параметру «json» и не будет работать (хотя, вероятно, выдаст вам более полезную ошибку «не удается найти данные для параметра») (при условии, конечно, отсутствия дополнительной маршрутизации).

Присвоив вашему строковому параметру имя, связующее устройство модели по умолчанию сможет сопоставить строку с именем параметра:

 $.ajax({ url: url, data: { json: "string" }});
  

Альтернативой является добавление связующего элемента модели, который будет принимать любую отправленную строку и передавать ее в единственный параметр — но вышеупомянутый, как правило, более чистый и простой в обслуживании.


Добавление [HttpPost] ограничивает действие только этим глаголом (таким образом, добавление [HttpPost][HttpGet] делает его непригодным для использования, поскольку это должно быть POST и это должно быть GET).


Если вы создаете свою форму из viewmodel, то вы можете использовать эту viewmodel непосредственно в действии:

 public ActionResult MyAction(MyViewModel viewmodel)
  

и передает напрямую:

 $.ajax({ url: url, data: $("form").serialize() });
  

и связующее устройство модели по умолчанию сопоставит имена ваших входных данных со свойствами viewmodel.

Комментарии:

1. Действительно фантастический ответ. Спасибо, что нашли время для его написания. Я думаю, что моя главная проблема заключалась в том, что связующий мог бы сопоставить имя переменной JS с именем параметра C #. Следовательно, я не думал, что вам нужно указывать имя для данных тела POST в JS.

2. Как ни странно, в некоторых случаях это работает, особенно если вы это делаете $.ajax({url:url, data: { json }}) , также должно работать … в Chrome — это специфично для браузера, поэтому всегда стоит добавлять data: { json: json } иначе вам будет трудно найти ошибки, которые работают для вас, но не для кого-то другого, пока несколько часов спустя вы не обнаружите, что они используют другой браузер… (первый опыт из рук!)