Here is the markup of my form:
<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>
Then this is the code of the controller:
[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");
}
As you can see I already used tag FromBody
, which does not seem to be helpful enough.
Here is the code of my model class:
public class NewGroupViewModel
{
[Required]
[MinLength(5)]
[MaxLength(20)]
public string Name { get; set; }
public string Members { get; set; }
}
The problem here is that newGroupViewModel
values are null, and that leads to an exception at line
var memberEmails = newGroupViewModel.Members.Split().ToArray();
and the rest of the controller's code is kinda useless for this topic.
Due to the fact that null value can not be split. By the way inputs values are correct. But the values can't be successfully be delivered to the controller's method.
As you can see I've tried using FromForm
tag, but it didn't help. Also I tried to reformat minor stuff as swapping some positioning of asp tags in inputs & labels (I've faced this problem before and that's how it was solved, but it doesn't work this time)
Asp.Net Core bind value by property names. In your View code, You use asp-for="NewGroup.Name"
tag helper in input
tag, This tag helper will generate name="NewGroup.Name"
in html automatically. So when you submit the from, the property names are NewGroup.Name
and NewGroup.Members
.
In your backend, you use NewGroupViewModel
to accept data, But the property names in NewGroupViewModel
are Name
and Members
, They can't match with NewGroup.Name
and NewGroup.Members
, So NewGroupViewModel
can't bind data.
In your ajax code, you specify property names are name
and members
, This is why backend can bind value from ajax code.
So in your view code, you just need to specify the name
attribute correctly, Then backend can bind the value successfully
<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">
BTW: Asp.Net Core MVC default bind value from form, So you don't need to add [FromForm]
attribute in your controller action.