Вот разметка моей формы:
<form asp-controller = "Group" asp-action = "Create" class = "new-group-form">
<div class = "input-section">
<label asp-for = "NewGroup.Name">Name</label>
<input asp-for = "NewGroup.Name" type = "text">
</div>
<input class = "invited-members" asp-for = "NewGroup.Members" type = "hidden" value = "">
<div class = "possible-members">
@foreach (var friend in Model.Friends)
{
<div class = "member">
<p>@friend.FriendEmail</p>
<button id = "@friend.FriendEmail" type = "button" class = "member__action invite">Invite</button>
</div>
}
</div>
<div class = "buttons">
<button type = "submit" class = "create">Create</button>
<button type = "button" class = "cancel">Cancel</button>
</div>
</form>
Тогда это код контроллера:
[Route("group/new-group")]
[IgnoreAntiforgeryToken]
[HttpPost]
public IActionResult Create([FromForm]NewGroupViewModel newGroupViewModel)
{
var memberEmails = newGroupViewModel.Members.Split().ToArray();
var ownerEmail = User.FindFirstValue(ClaimTypes.Email);
if (ModelState.IsValid && memberEmails.Length >= 3)
{
var newGroup = _db.Groups.Add(new Group
{
Name = newGroupViewModel.Name,
OwnerId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier))
});
_db.SaveChanges();
foreach (var member in memberEmails)
{
_db.GroupParticipants.Add(new GroupParticipant
{
UserId = _db.Users.First(x => x.Email == member).Id,
GroupId = newGroup.Entity.Id,
IsOwner = (member == ownerEmail)
});
}
_db.SaveChanges();
}
return RedirectToAction("Index", "Boards");
}
Как видите, я уже использовал тег FromBody, который кажется недостаточно полезным.
Вот код моего модельного класса:
public class NewGroupViewModel
{
[Required]
[MinLength(5)]
[MaxLength(20)]
public string Name { get; set; }
public string Members { get; set; }
}
Проблема здесь в том, что значения newGroupViewModel равны нулю, и это приводит к исключению в строке
var memberEmails = newGroupViewModel.Members.Split().ToArray();
а остальной код контроллера как бы бесполезен для этой темы.
Из-за того, что нулевое значение нельзя разделить. Кстати, входные значения правильные. Но значения не могут быть успешно доставлены в метод контроллера.
Как видите, я пробовал использовать тег FromForm, но это не помогло. Также я попытался переформатировать второстепенные вещи, поменяв местами позиционирование тегов asp во входных данных и метках (я сталкивался с этой проблемой раньше, и именно так она была решена, но на этот раз это не работает)
ну спасибо за совет конечно, но это не поможет в этой самой проблеме
Что вы видите на вкладке «Сеть» в DevTools вашего браузера? Ваш элемент <form> отображается с помощью method = "post"? Когда вы устанавливаете точку останова в первой строке метода действия Create, что вы видите в this.Request.Form в отладчике?
<form method = "post" class = "new-group-form active" action = "/group/new-group"> так выглядит обработанная форма. и да, как я уже упоминал, скрытый ввод (для участников) получает правильные значения в devtools. говоря об этом.Request.Form я вижу 3 ключа: NewGroup.Name, NewGroup.Members + проверочный токен
Я думаю, что важно уточнить, что метод получает саму модель. Но New Group.Name, New Group.Members имеют значение null. Убедился в этом при отладке.
Какое свойство называется NewGroup? NewGroupViewModel совпадает с типом @model на вашей .cshtml странице? Вы можете использовать только asp-for = "" (или Html.AnythingFor( m => m.Foo ), когда модель формы также является @model для представления (да, это глупое ограничение ASP.NET MVC, но есть обходные пути).
Если я вас правильно понял, то public class BoardsViewModel { public NewGroupViewModel NewGroup { get; set; } это та часть модели из файла, где произошла ошибка с формой. и.. да. они одинаковые (кстати извините за плохое знание английского :()





Решено с помощью ajax-запроса
function createGroup(name, members) {
$.ajax({
type: "POST",
url: "group/new-group",
data: {
name: name,
members: members
}
});
}
До сих пор не понимаю, почему это не работает по-старому
Значение привязки Asp.Net Core по именам свойств. В вашем коде просмотра вы используете помощник тега asp-for = "NewGroup.Name" в теге input, этот помощник тега будет автоматически генерировать name = "NewGroup.Name" в html. Поэтому, когда вы отправляете имя, имена свойств будут NewGroup.Name и NewGroup.Members.
В вашем бэкенде вы используете NewGroupViewModel для приема данных, но имена свойств в NewGroupViewModel — это Name и Members, они не могут совпадать с NewGroup.Name и NewGroup.Members, поэтому NewGroupViewModel не может связывать данные.
В вашем коде ajax вы указываете имена свойств name и members, поэтому бэкенд может связывать значение из кода ajax.
Таким образом, в вашем коде просмотра вам просто нужно правильно указать атрибут name, тогда бэкэнд сможет успешно связать значение.
<div class = "input-section">
<label asp-for = "NewGroup.Name">Name</label>
<input name = "Name" type = "text">
</div>
<input class = "invited-members" name = "Members" type = "hidden" value = "xxxx">
Кстати: значение привязки Asp.Net Core MVC по умолчанию из формы, поэтому вам не нужно добавлять атрибут [FromForm] в действие вашего контроллера.
Большое спасибо! Итак, я должен использовать тег name напрямую (без использования asp-for) в моих формах ввода, когда запрос (в данном случае NewGroupViewModel) является свойством модели, а не самой моделью?
MinLengthиMaxLengthпредназначены для EF - для ASP.NET ViewModels вам нужно использовать[StringLength](который также поддерживает как минимальную, так и максимальную длину).