When saving the details from the view, the details is not binding into the nested class (BOUser) in ViewModel.The nested class data is showing null(Refer the debug result image). I am using .net core 6 in Mac for the development. Please help me out what I am missed in this coding.
Controller Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using NearMeBuy.Models.Masters.ViewModels;
namespace NearMeBuyWebApp.Areas.Admin.Controllers
{
[Area("Admin")]
public class TestOPSController : Controller
{
public IActionResult Index()
{
RegisterVM registerVM = new RegisterVM()
{
ApplicationRoles = null,
BOUser = new(),
DepartmentMaster = null,
Mode = 1
};
return View(registerVM);
}
[HttpPost]
public IActionResult Index(RegisterVM vM )
{
if (ModelState.IsValid)
{
return View("Hi");
}
return View();
}
}
}
View Model Class
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.Rendering;
using NearMeBuy.Models.Tokens.User;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NearMeBuy.Models.Masters.ViewModels
{
public class RegisterVM
{
public int Mode { get; set; }
//public RegisterModel RegisterModel { get; set; }
public BOUser BOUser { get; set; }
[ValidateNever]
public IEnumerable<SelectListItem> ApplicationRoles { get; set; }
[ValidateNever]
public IEnumerable<SelectListItem> DepartmentMaster { get; set; }
}
}
BOUser Class
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.EntityFrameworkCore;
namespace NearMeBuy.Models.Masters
{
public class BOUser
{
public string UserId { get; set; }
[Required(ErrorMessage = "First Name can't be empty")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Last Name can't be empty")]
public string LastName { get; set; }
[Required(ErrorMessage = "Email can't be empty")]
public string Email { get; set; }
[Required(ErrorMessage = "Phone can't be empty")]
public string PhoneNo { get; set; }
[Required(ErrorMessage = "Username can't be empty")]
public string UserName { get; set; }
[Required(ErrorMessage = "Account Confirmation can't be empty")]
public bool AccountConfirmed { get; set; } = false;
/// <summary>
/// The user type field to store the type of user 1: for BackOffice User , 2: for Supplier Registration, 3: for End Users/ Customers.
/// </summary>
[Required(ErrorMessage = "User Type Field can't be empty")]
[Comment("The user type field to store the type of user 1: for BackOffice User , 2: for Supplier Registration, 3: for End Users/ Customers., 0: for Administrator")]
public Int16 UserType { get; set; }
[Required(ErrorMessage = "Password can't be empty")]
public string Password { get; set; }
[ValidateNever]
public string? returnUrl { get; set; }
}
}
View
#model RegisterVM
#{
ViewData["Title"] = "Register Page";
}
<form id="registrationForm" asp-controller="TestOPS" asp-action="Index" method="post">
<div class="card">
<div class="card-header">
<h5 class="card-title">
#{
#if (#Model.Mode == 1)
{
<b>Create</b>
}
else if (#Model.Mode == 2)
{
<b>Edit</b>
}
else if (#Model.Mode == 3)
{
<b>Delete</b>
}
}
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-12">
<input type="hidden" id="hdnMode" asp-for="Mode" />
<input type="hidden" id="hdnUserId" asp-for="BOUser.UserId" />
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>First Name</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="#Model.BOUser.FirstName" name="firstname" />
<span asp-validation-for="BOUser.FirstName" class="text-danger"></span>
</div>
<div class="col-lg-2">
<label>Last Name</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="BOUser.LastName" name="lastname" />
<span asp-validation-for="BOUser.LastName" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Email</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="BOUser.Email" name="email" />
<span asp-validation-for="BOUser.Email" class="text-danger"></span>
</div>
<div class="col-lg-2">
<label>Phone No.</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="BOUser.PhoneNo" name="phoneno" />
<span asp-validation-for="BOUser.PhoneNo" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>User Name</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="BOUser.UserName" name="username" />
<span asp-validation-for="BOUser.UserName" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Password</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="BOUser.Password" name="password" id="txtPassword" />
<span asp-validation-for="BOUser.Password" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Confirm Password</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" name="confirmPassword" />
<span asp-validation-for="BOUser.Password" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Roles</label>
</div>
<div class="col-lg-5">
<table>
#if (Model.ApplicationRoles != null)
{
#foreach (var roles in Model.ApplicationRoles)
{
<tr>
<td>
<input id="#roles.Value" type="checkbox" name="roles" value="#roles.Value" checked="#roles.Selected" asp-for="#roles.Selected" />
</td>
<td>
<label asp-for="#roles.Value">#roles.Text</label>
</td>
</tr>
}
}
</table>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Department</label>
</div>
<div class="col-lg-5">
<table>
#if (Model.DepartmentMaster != null)
{
#foreach (var dept in Model.DepartmentMaster)
{
<tr>
<td>
<input id="#dept.Value" type="checkbox" name="departments" value="#dept.Value" checked="#dept.Selected" asp-for="#dept.Selected" />
</td>
<td>
<label asp-for="#dept.Value">#dept.Text</label>
</td>
</tr>
}
}
</table>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Approved</label>
</div>
<div class="col-lg-4">
<input type="checkbox" asp-for="BOUser.AccountConfirmed" />
</div>
</div>
</div>
<div class="card-footer text-right">
<input type="submit" class="btn btn-secondary" value="Save" />
</div>
</div>
</form>
#section Scripts{
<script src="~/js/regLogin.js"></script>
}
Debug Result
enter image description here
Remove a name attirbute from ALL web controls, for example should be just
<input class="form-control form-control-sm" asp-for="BOUser.LastName" />
I've been away from ASP.NET MVC for a while so forgotten some of the basics.
I have scoured SO for an answer, but none really seem to apply/work so this may seem like a duplicate question but it's really not, perhaps I just can't see the wood through the trees. I know I'm missing something obvious but cant remember what
I have a partial that I pass the model to that updates a property on the model (AddressDetails & ContactDetails).
Main page
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div
#await Html.PartialAsync("../AddressDetails/Create.cshtml", Model)
#await Html.PartialAsync("../ContactDetails/Create.cshtml", Model)
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
And partial page
#model CareHome.Models.CareHomes
<div class="form-group">
<h4>AddressDetails</h4>
<hr />
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="AddressDetails.NumberStreetName" class="control-label"></label>
<input asp-for="AddressDetails.NumberStreetName" class="form-control" />
<span asp-validation-for="AddressDetails.NumberStreetName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AddressDetails.Locality" class="control-label"></label>
<input asp-for="AddressDetails.Locality" class="form-control" />
<span asp-validation-for="AddressDetails.Locality" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AddressDetails.Town" class="control-label"></label>
<input asp-for="AddressDetails.Town" class="form-control" />
<span asp-validation-for="AddressDetails.Town" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AddressDetails.PostCode" class="control-label"></label>
<input asp-for="AddressDetails.PostCode" class="form-control" />
<span asp-validation-for="AddressDetails.PostCode" class="text-danger"></span>
</div>
This is working fine when I post data back to the controller
However, I want to reuse the partial which means I want to replace
#model CareHome.Models.CareHomes
in the partial with the property class (see further below) that the model uses.
So when I change it to
main
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div
#await Html.PartialAsync("../AddressDetails/Create.cshtml", Model.AddressDetails)
#await Html.PartialAsync("../ContactDetails/Create.cshtml", Model.ContactInfo)
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
note that im passing the property through to the partial now not the model
#model CareHome.Models.AddressDetails
<div class="form-group">
<h4>AddressDetails</h4>
<hr />
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="NumberStreetName" class="control-label"></label>
<input asp-for="NumberStreetName" class="form-control" />
<span asp-validation-for="NumberStreetName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Locality" class="control-label"></label>
<input asp-for="Locality" class="form-control" />
<span asp-validation-for="Locality" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Town" class="control-label"></label>
<input asp-for="Town" class="form-control" />
<span asp-validation-for="Town" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PostCode" class="control-label"></label>
<input asp-for="PostCode" class="form-control" />
<span asp-validation-for="PostCode" class="text-danger"></span>
</div>
iv now changed the partial to use
#model CareHome.Models.AddressDetails
but when I post this to the controller it comes back null
I tried a million variations on the binding
// POST: CareHomes/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
//Create([Bind("CareHomesId,Name,ContactName,ContactNumber")] CareHomes careHomes)
public async Task<IActionResult> Create([Bind( "CareHomes,AddressDetails,ContactDetails")] CareHomes careHomes)
{
if (ModelState.IsValid)
{
_context.Add(careHomes);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["AddressDetailsId"] = new SelectList(_context.AddressDetails, "AddressDetailsId", "NumberStreetName", careHomes.AddressDetailsId);
ViewData["ContactDetailsId"] = new SelectList(_context.ContactDetails, "ContactDetailsId", "ContactName", careHomes.ContactDetailsId);
return View(careHomes);
}
but when I evaluate the ModelState I can see it's always missing. As the propertys of the model bind ok when i pass the model though why do they then not bind when i pass the property though
my classes are like so
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace CareHome.Models
{
public class CareHomes
{
[Required]
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CareHomesId { get; set; }
[Required]
[Column(TypeName = "VARCHAR(256)")]
[StringLength(256, MinimumLength = 3)]
public string Name { get; set; }
public int? AddressDetailsId { get; set; }
public AddressDetails AddressDetails { get; set; }
public int? ContactDetailsId { get; set; }
public ContactDetails ContactInfo { get; set; }
public ICollection<Staff>? StaffMembers { get; set; }
}
}
and one of the properties in question
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace CareHome.Models
{
public class AddressDetails
{
[Required]
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AddressDetailsId { get; set; }
[Required]
[Column(TypeName = "VARCHAR(256)")]
[StringLength(256, MinimumLength = 3)]
[Display(Name = "House No & Street Name")]
public string NumberStreetName { get; set; }
[Column(TypeName = "VARCHAR(256)")]
[StringLength(256, MinimumLength = 3)]
public string? Locality { get; set; }
[Required]
[Column(TypeName = "VARCHAR(256)")]
[StringLength(256, MinimumLength = 3)]
public string Town { get; set; }
[Required]
[Column(TypeName = "VARCHAR(16)")]
[StringLength(16, MinimumLength = 4)]
[RegularExpression(#"^(([A-Z]{1,2}\d[A-Z\d]?|ASCN|STHL|TDCU|BBND|[BFS]IQQ|PCRN|TKCA) ?\d[A-Z]{2}|BFPO ?\d{1,4}|(KY\d|MSR|VG|AI)[ -]?\d{4}|[A-Z]{2} ?\d{2}|GE ?CX|GIR ?0A{2}|SAN ?TA1)$", ErrorMessage = "Please enter a valid UK post code in upper case")]
public string PostCode { get; set; }
public CareHomes? CareHomes { get; set; }
}
}
I have tried adding bind animations like
[BindProperty]
to the property and adding hidden fields in the partual
#Html.HiddenFor(m => m.AddressDetailsId)
#Html.HiddenFor(m => m.AddressDetails)
As per some suggestions from some of the many SO searches I did, but no dice....so please...what am I missing?
I even tried #html.EditorFor but that seems to have the same problem
EDIT
Using #Jonesopolis suggestion I can see from the form being posted back when it uses the model:
?this.Request.Form.ToArray()
{System.Collections.Generic.KeyValuePair<string, Microsoft.Extensions.Primitives.StringValues>[11]}
...
[4]: {[AddressDetails.CareHomes, {}]}
[5]: {[AddressDetailsId, {}]}
[6]: {[AddressDetails.NumberStreetName, {sad}]}
[7]: {[AddressDetails.Locality, {sad}]}
[8]: {[AddressDetails.Town, {wales}]}
[9]: {[AddressDetails.PostCode, {CF83 8RD}]}
vs when i pass the property
?this.Request.Form.ToArray()
{System.Collections.Generic.KeyValuePair<string, Microsoft.Extensions.Primitives.StringValues>[11]}
...
[4]: {[CareHomes, {}]}
[5]: {[AddressDetailsId, {0}]}
[6]: {[NumberStreetName, {test street}]}
[7]: {[Locality, {}]}
[8]: {[Town, {wales}]}
[9]: {[PostCode, {CF83 8RD}]}
so clearly the "AddressDetails" is missing so MVC cant map the propery to the CareHomes class object on the binding because the property name is missing. So i know what the issue is not how to fix it though, How do I set the property name on the partual propertys so they map back to the parent object class. I though about a costom binder but not having much luck figuring that one out.
On a side note, intrestingly enough if in the partent model I do this :
#Html.EditorFor(m => m.AddressDetails.NumberStreetName)
then bind like so
public async Task<IActionResult> Create([Bind(include: "CareHomes,AddressDetails")] CareHomes careHomes)
I can at least get the EditorFor to pull though on the parent
Finally worked it out, seems model binding wasn't the issue, I just had to set the id and name properties on the form controls in the partial to match that of the object on the model action, e.g. id="AddressDetails_NumberStreetName" name="AddressDetails.NumberStreetName"
so adding
<div class="form-group">
<label asp-for="NumberStreetName" class="control-label"></label>
<input asp-for="NumberStreetName" id="AddressDetails_NumberStreetName" name="AddressDetails.NumberStreetName" class="form-control" />
<span asp-validation-for="NumberStreetName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Locality" class="control-label"></label>
<input asp-for="Locality" id="AddressDetails_Locality" name="AddressDetails.Locality" class="form-control" />
<span asp-validation-for="Locality" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Town" class="control-label"></label>
<input asp-for="Town" id="AddressDetails_Town" name="AddressDetails.Town" class="form-control" />
<span asp-validation-for="Town" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Postcode" class="control-label"></label>
<input asp-for="Postcode" id="AddressDetails_Postcode" name="AddressDetails.Postcode" class="form-control" />
<span asp-validation-for="Postcode" class="text-danger"></span>
</div>
allows it to properly map to the contoller model
public async Task<IActionResult> Create([Bind(include: "CareHomes, Name,AddressDetails, ContactInfo")] CareHomes careHomes)
I worked it out when I put the partial mark up in the main form and looked at the HTML markup and compared it to when it was a partial. I hope this helps someone else someday
I'm using a regular html form instead of #html.BeginForm and I have these 2 form tags in my Create.cshtml view file.
I was experimenting with routing, but my post doesn't seem to get the values even if I bind the properties. I've tried in vain but I can't seem to make this work, and can't find the answer from googling.
Create.cshtml
#model Actor
#{
ViewData["Title"] = "Add";
}
<section class="container-xl justify-content-center col-lg-5 col-md-8 col-sm-10">
<div class="row">
<span class="text-center mb-3">
<h5>Add a new record</h5>
</span>
<div>
<form>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
</form>
<div class="form-group">
<label class="form-label" asp-for="ProfilePictureUrl">Profile Picture</label>
<input class="mb-2 form-control" type="text" asp-for="ProfilePictureUrl" placeholder="Profile picture" />
</div>
<div class="form-group">
<label class="form-label" asp-for="FullName">Full Name</label>
<input class="mb-2 form-control" type="text" placeholder="Full name" asp-for="FullName" />
</div>
<div class="form-group">
<label class="form-label" asp-for="Bio">Biography</label>
<input class="form-control" type="text" placeholder="Bio" asp-for="Bio" />
</div>
<form>
<div class="form-group mt-3">
<a class="btn btn-outline-secondary" asp-action="Index">Show All</a>
<input asp-action="Create2" class="float-end btn btn-outline-success" type="submit" value="Create" />
</div>
</form>
</div>
</div>
</section>
Actor.cs
using System.ComponentModel.DataAnnotations;
namespace MovieProject.Models
{
public class Actor
{
[Key]
public int ActorId { get; set; }
[Display(Name ="Profile Picture")]
public string ProfilePictureUrl { get; set; }
[Display(Name ="Full Name")]
public string FullName { get; set; }
[Display(Name ="Biography")]
public string Bio { get; set; }
}
}
ActorController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MovieProject.Data;
using MovieProject.Data.Services;
using MovieProject.Models;
namespace MovieProject.Controllers
{
public class ActorController : Controller
{
private readonly IActorService _service;
public ActorController(IActorService service)
{
_service = service;
}
[HttpPost]
public IActionResult Create2([Bind("ProfilePictureUrl,FullName,Bio")] Actor actorItem)
{
return View("Create");
}
public IActionResult Create()
{
return View();
}
}
}
The methods are getting hit but the post data is null.
Another question is, instead of using MVC convention, can I use a different method name for get and post that is not the same as the view name? How can I get initially load the page for GET using routing that would work in a different view name?
Thanks
can I use a different method name for get and post that is not the
same as the view name?
Yes, you can.
How can I get initially load the page for GET using routing that would
work in a different view name?
return to this view.
public IActionResult Create()
{
return View("aa");
}
Below is a work demo, you can refer to it.
In controller:
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create2(Actor actorItem)
{
return View();
}
Create view:
#model nnnn.Models.Actor
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Actor</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create2">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="ActorId" class="control-label"></label>
<input asp-for="ActorId" class="form-control" />
<span asp-validation-for="ActorId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ProfilePictureUrl" class="control-label"></label>
<input asp-for="ProfilePictureUrl" class="form-control" />
<span asp-validation-for="ProfilePictureUrl" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FullName" class="control-label"></label>
<input asp-for="FullName" class="form-control" />
<span asp-validation-for="FullName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Bio" class="control-label"></label>
<input asp-for="Bio" class="form-control" />
<span asp-validation-for="Bio" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
result:
I recently started learning Asp.Net with Razor Pages and I'm working on this project where users can enter his name last name and pin code for his credit card and if inputs are in the database, it redirects him to user page and shows him how much money he has on his card.
But my validation is wrong, even when input is not in the database or is different from values in the database it redirects me to User page.Can someone help me to make my validation right.
Thanks in advance.
Here is all my code:
Index page:
#page
#model BanlAcc.Pages.BankAcc.IndexModel
<br />
<h2 class="text-info">Enter your data</h2>
<div class=" border container" style="padding: 30px;">
<form method="post">
<div class="text-danger" asp-validation-summary="ModelOnly"></div>
<div class="form-group row">
<div class="col-3">
<label asp-for="Account.Name"></label>
</div>
<div class="col-6">
<input asp-for="Account.Name" class="form-control" />
</div>
</div>
<span class="text-danger" asp-validation-for="Account.Name"></span>
<div class="form-group row">
<div class="col-3">
<label asp-for="Account.Surname"></label>
</div>
<div class="col-6">
<input asp-for="Account.Surname" class="form-control" />
</div>
</div>
<span class="text-danger" asp-validation-for="Account.Surname"></span>
<div class="form-group row">
<div class="col-3">
<label asp-for="Account.Pin"></label>
</div>
<div class="col-6">
<input asp-for="Account.Pin" class="form-control" />
</div>
</div>
<span class="text-danger" asp-validation-for="Account.Pin"></span>
<div class="form-group row">
<div class="col-3">
<input type="submit" value="Check" class="btn btn-primary form-control" />
</div>
</div>
</form>
</div>
#section Scripts{
<partial name="_ValidationScriptsPartial" />
}
Index.cshtml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BanlAcc.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
namespace BanlAcc.Pages.BankAcc
{
public class IndexModel : PageModel
{
private readonly ApplicationDbContext _db;
private object _userRepository;
public IndexModel(ApplicationDbContext db)
{
_db = db;
}
[BindProperty]
public Account Account { get; set; }
public void OnGet()
{
}
public IActionResult OnPost()
{
if (ModelState.IsValid)
{
return RedirectToPage("User");
}
else
{
return Page();
}
}
}
}
Account.cs:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace BanlAcc.Model
{
public class Account
{
[Key]
public int Id { get; set; }
[Required, MaxLength(20)]
public string Name { get; set; }
[Required, MaxLength(20)]
public string Surname { get; set; }
[Required]
public int Pin { get; set; }
public int Amount { get; set; }
}
}
User page:
#page
#model BanlAcc.Pages.BankAcc.AccountModel
<br />
<h2 class="text-info">Wellcome</h2>
I have an ASP.NET Core application with Entity framework 7.
I am using Data annotations to display warnings when editing content on the website.
When adding the input field and their respective warning span in a loop this didn't work.
It is blocking the submit, it is not showing any warning.
Am I doing something wrong?
my code:
Razor view:
#model Receptenboek.Models.RecipeViewModels.RecipeEdit
#{
ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>Recipe</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Recipe.ID" />
<input type="hidden" asp-for="Recipe.Ingredients" />
<div class="form-group">
<label asp-for="Recipe.Name" class="control-label"></label>
<input asp-for="Recipe.Name" class="form-control" />
<span asp-validation-for="Recipe.Name" class="text-danger"></span>
</div>
<div class="form-group">
<h3 asp-for="Book" class="control-label">Book</h3>
<select asp-for="Recipe.RecipeBookID" asp-items="#(new SelectList(Model.Books, "ID", "BookName", Model.Recipe.RecipeBookID))"></select><br />
<span asp-validation-for="Books" class="text-danger"></span>
</div>
<div id="fields" class="form-actions">
#foreach (Recipe_Ingredient ri in Model.Recipe.Ingredients)
{
<div id="IngredientDiv">
<label class="control-label">Ingredient name </label><br />
<select name="ingredients" asp-for="#ri.IngredientID" asp-items="#(new SelectList(Model.Ingredients, "ID", "Name"))"></select><br />
<label class="control-label">Amount </label>
<input name="Amount" class="form-control" asp-for="#ri.Amount" asp-route-amounts="#ViewData["amounts"]" />
<span asp-validation-for="#ri.Amount" class="text-danger"></span>
<hr />
</div>
}
</div>
<span class="text-danger">#ViewData["Warning"]</span><br/>
<a onclick="duplicate()">Add Ingredient</a>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Receptenboek.Models.RecipeViewModels
{
public class RecipeEdit
{
public Recipe Recipe { get; set; }
public ICollection<Ingredient> Ingredients { get; set; }
public ICollection<RecipeBook> Books { get; set; }
}
}
Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Receptenboek.Models
{
public class Recipe
{
public int ID { get; set; }
[Required]
[Display(Name = "Book")]
public int RecipeBookID { get; set; }
[Required]
[Display(Name = "Recipe Name")]
public string Name { get; set; }
public ICollection<Recipe_Ingredient> Ingredients { get; set; }
public RecipeBook Book { get; set; }
}
}
Because you are using a foreach loop, your code will render HTML with duplicate IDs. This will cause the model binding to fail on POST. You need to replace it with a for loop and then either;
Use the index to distinguish the different items such as in this solution: ASP.NET Core 1.0 POST IEnumerable<T> to controller
Use Html.EditorFor such as in this documentation: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms#the-input-tag-helper