При использовании fetch, не преобразовывается объект json в модель в контроллере. Почему так происходит?
Всем привет, я новичок в ASP.NET MVC, я пытаюсь послать данные на сервер, через метод javascript - fetch, а не через обычные asp-controller, asp-action, для того чтобы взаимодействовать с response от сервера, чтобы в зависимости от статуса ответа выводить разные всплывающие окна. Моя форма, с моим методом fetch выглядит следующим образом:
<form id="personalProfileFormId">
<input class="info-user-input" asp-for="Id" hidden="hidden"/>
<input class="info-user-input" asp-for="IsExamCompleted" hidden="hidden" />
<input class="info-user-input" asp-for="FinalGrade" hidden="hidden" />
<div class="mb-3">
Логин : <input class="info-user-input personal-profile-input-disabled" asp-for="Login" type="text">
</div>
<div class="mb-3">
Имя: <input class="info-user-input" asp-for="Name" class="form-control" type="text">
</div>
<div class="mb-3">
Фамилия: <input class="info-user-input" asp-for="Surname" class="form-control" type="text">
</div>
<div class="mb-3">
<div class="d-flex justify-content-between card-buttons-group">
<button type="submit" class="btn btn-primary" id='updateInfoId'>Обновить информацию</button>
</div>
</div>
<p>
Окончательный результат: @if (Model.IsExamCompleted == false)
{
<text>не получен</text>
}
else
{
<text>@Model.FinalGrade баллов из 100</text>
}
</p>
<button type="button" align="center" class="btn btn-gradient text-white"
onclick="openModal({ url: '/PersonalProfile/GetLessonRecords', modalId: 'modalWindow'})"
data-toggle="ajax-modal" data-target="Modal">
Список оценок
</button>
<br />
<p>Лекций пройдено: <input asp-for="LessonsCompleted" class="personal-profile-input-disabled info-user-input" disabled="disabled" /> </p>
</form>
Когда я отправляю данные через fetch, код javascript вот:
document.getElementById("personalProfileFormId").addEventListener("submit", (event) => {
event.preventDefault();
var updateFormInputs = document.getElementsByClassName('info-user-input');
var updateFormData = {};
for (let i = 0; i < updateFormInputs.length; i++) {
let input = updateFormInputs[i];
updateFormData[input.id] = input.value;
}
var jsonData = JSON.stringify(updateFormData);
const response = fetch('/PersonalProfile/UpdateInfo', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: jsonData
});
if (response.ok) {
Swal.fire({
title: 'Информация',
text: response.description,
icon: 'success',
confirmButtonText: 'Окей'
})
}
else {
Swal.fire({
title: 'Информация',
text: response.description,
icon: 'error',
confirmButtonText: 'Окей'
})
}
});
, в контроллере модель получает null, вот код контроллера:
[HttpPost]
public async Task<IActionResult> UpdateInfo([FromBody] ProfileViewModel model)
{
//return View();
if (ModelState.IsValid)
{
var response = await _personalProfileService.UpdateInfo(model);
if (response.StatusCode == Domain.Enum.StatusCode.OK)
{
return Json(new { description = response.Description });
}
}
return StatusCode(StatusCodes.Status500InternalServerError);
}
Вот код модели:
public class ProfileViewModel
{
public int Id { get; set; }
public string Login { get; set; }
[Required(ErrorMessage = "Введите имя")]
[MinLength(2, ErrorMessage = "Длина имени должна быть больше двух символов")]
[MaxLength(25, ErrorMessage = "Длина имени должна быть меньше 25 символов")]
public string Name { get; set; }
[Required(ErrorMessage = "Введите фамилию")]
[MinLength(2, ErrorMessage = "Длина фамилии должна быть больше двух символов")]
[MaxLength(25, ErrorMessage = "Длина фамилии должна быть меньше 25 символов")]
public string Surname { get; set; }
public float FinalGrade { get; set; }
public bool IsExamCompleted { get; set;}
public int LessonsCompleted { get; set; }
}
Но. Когда я ставлю в параметр контроллера вместо ProfileViewModel тип object, то в object пишет что-то вроде такого: ValueKind = Object : "{"Id":"2","IsExamCompleted":"true","FinalGrade":"26,5","Login":"CommonUser02","Name":"maximka","Surname":"maximoff","LessonsCompleted":"5"}".
Моя суть вопроса заключается в следующем, как можно преобразовывать это сразу это в ProfileViewModel? Я видел что в других примерах оно преобразовывается. Что я делаю не так, и другой вопрос, возможно ли провзаимодействовать с response от формы без использования fetch, а используя стандартную форму на манер ASP.NET, c asp-controller и asp-action, и вывести всплывающие окна swal.fire, так как я это делаю с fetch в примере?
Ответы (2 шт):
Попробуйте сделать так: JS:
var response = fetch('/PersonalProfile/UpdateInfo', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: {
"Params": jsonData
}
});
C#:
JsonSerializer.Deserialize<ProfileViewModel>(Request.Body["Params"]);
Т.е. нужно в JS в body нужно не просто вставить свой JSON, а обозвать его как-то, например "Params". И в C# достать с помощью Request.Body["Params"]
Выяснил что было не так, во первых надо было сделать async функцию и await fetch. И во вторых я считывал переменную "FinalGrade":"26,5" вот так, а должен был вот так: "FinalGrade":"26.5" Я переписал javascript код следующим образом:
document.getElementById("updateInfoId").addEventListener("click", async (event) => {
event.preventDefault();
var updateFormData = {
Id: parseInt(document.getElementById("Id").value),
IsExamCompleted: Boolean(document.getElementById("IsExamCompleted").value),
FinalGrade: parseFloat(document.getElementById("FinalGrade").value.replace(/,/g, '.')),
Login: document.getElementById("Login").value,
Name: document.getElementById("Name").value,
Surname: document.getElementById("Surname").value,
LessonsCompleted: parseInt(document.getElementById("LessonsCompleted").value)
};
const response = await fetch('/PersonalProfile/UpdateInfo', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updateFormData)
});
const responseBody = await response.json();
Swal.fire({
title: 'Информация',
text: responseBody.description,
icon: response.ok ? 'success' : 'error',
confirmButtonText: 'Окей'
});
});