MVC Model data is not binding - c#

I have created form to add customer. I rendered customer page with Viewmodel. View Model class as follows,
public class CustomerViewModel
{
public IEnumerable<MemberShipType> MemberShipTypes { get; set; }
public Customer Customers { get; set; }
}
public class Customer
{
[Display(Name ="Customer ID")]
public int CustomerId { get; set; }
[Required(ErrorMessage = "Please enter customer name")]
[StringLength(255)]
[Display(Name ="Customer Name")]
public string CustomerName { get; set; }
public MemberShipType MemberShipType { get; set; }
[Required(ErrorMessage = "Please select membership type")]
[Display(Name = "Membership Type")]
public byte MembershipTypeId { get; set; }
}
public class MemberShipType
{
[Display(Name ="Membership Id")]
public byte Id { get; set; }
[Required]
[Display(Name = "Subscription Plan")]
public string Name { get; set; }
}
After adding that class, we have created Action to save customer form data using a single model class(Not viewModel)
I have created Customer form using Viewmodel to display with Membership type data.
UI is rendering fine with the below code. But, I am not able to get the model data in the action method.
If I directly use the viewmodel in the action data is coming fine. The problem needs to map all the view model property to a particular model.
It's required more time to map model property each time.
Can any know how to directly use entity framework add method with customer Model(Not View model)
#using (Html.BeginForm("Save", "Customer", FormMethod.Post))
{
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Customers.CustomerName, htmlAttributes:
new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(m => m.Customers.CustomerName,
new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(m => m.Customers.CustomerName, "",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Customers.MembershipTypeId, htmlAttributes:
new { #class = "control-label col-md-2" })
<div class="col-lg-10">
#Html.DropDownListFor(m => m.Customers.MembershipTypeId,
new SelectList(Model.MemberShipTypes, "Id", "Name"),
"Please Select", new {#class = "form-control"})
#Html.ValidationMessageFor(m => m.Customers.MembershipTypeId,
"",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<input type="reset" value="Reset" class="btn btn-default" />
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>
</div>
}
The below action model always return null.
[System.Web.Mvc.HttpPost]
public ActionResult Save(Customer customer)
{
if (customer.CustomerId == 0)
{
_context.Customer.Add(customer);
_context.SaveChanges();
}
}
I am getting a Customer model is null. If I pass customerViewModel data is coming. Can anyone know the answer on how to directly get the data in the model class?

Since you're binding the view to a model of CustomerViewModel and you're using the HTML helpers EditorFor (lambda overload), you should expect that same model in return on your POST. When you use LabelFor and EditorFor, the automatic naming will probably give you something like "Customers_CustomerName" so it can put your view model back together again.
One solution is to change your expected model on your save method to be a 'CustomerViewModel' and just use the .Customer property to get the data.
[System.Web.Mvc.HttpPost]
public ActionResult Save(CustomerViewModel model)
{
if (model.Customer.CustomerId == 0)
{
_context.Customer.Add(model.Customer);
_context.SaveChanges();
}
}
Another option is to name your input fields manually to reflect properties of the 'Customer' model directly and it will map them into a "Customer" model for you on POST. eg Instead of #Html.LabelFor(m => m.Customers.CustomerName you'd just use #Html.EditorFor("CustomerName", Model.Customers.CustomerName)
<div class="form-group">
#Html.LabelFor(m => m.Customers.CustomerName, htmlAttributes:
new { #class = "control-label col-md-2" })
<div class="col-md-10">
*********EDIT HERE --> #Html.TextBox("CustomerName", Model.Customers.CustomerName
new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(m => m.Customers.CustomerName, "",
new { #class = "text-danger" })
</div>
</div>

I got the solution for this issue. The reason for the problem is, I've created controller and Model in the same name. So, I've changed Model name with different alias in Viewmodel like below,
public class CustomerViewModel
{
public IEnumerable<MemberShipType> MemberShipTypes
{ get; set; }
public ProductionCustomer productionCustomers
{ get; set; }
}
If we use model object in controller to Get/POST it will work even if we rendered the form with ViewModel(Multiple Model). By default mvc will identify the model to post in the form.

Related

How to post multiselect option and save in Db using ASP.Net MVC?

I am trying to post multiselect option and save it in Db. I did try few options but same did not work.
Client model class:
public string OwnerName { get; set; }
public string UnitNumber { get; set; }
public int AreaId { get; set; } // This is a foreign key
public string AreaName { get; set; } // This will display dropdown list
Controller action method - I am using FormCollection to collect the AreaId from the view to post in Client model class:
public ActionResult ClientDeal(Client model, FormCollection formCollection)
{
string selectedArea = formCollection["AreaId"];
}
Here is the view with the field I am having trouble with
<div class="form-group col-md-4">
<label class="control-label col-md-8 font-weight-bold">Area</label>
<div class="col-md-10">
#Html.DropDownListFor(model => model.AreaId, Model.Areas, new { #class = "form-control selectpicker select", #multiple = "multiple" })
#Html.ValidationMessageFor(model => model.Areas, "", new { #class = "text-danger" })
</div>
</div>
Thank you in advance
this line is wrong:
#Html.DropDownListFor(model => model.AreaId, Model.Areas, new { #class = "form-control selectpicker select", #multiple = "multiple" })
You need to bind the dropdown to a collection property, have something like:
public int[] AreaIds { get; set; }
and bind it like this:
#Html.DropDownListFor(model => model.AreaIds,
There's no need to set the value Model.Areas in the helper declaration, just set in the ViewModel when you return the view:
return View(new Client { AreaIds = "what you now have in Model.Areas" }
There's no need to use FormCollection

How to update table properties from related table in ASP.NET MVC

I've recently started with ASP.NET and I must say that I like it a lot. But in every relationship, you must hit some obstacle here and there. Here is mine:
My starting project includes creating simple schools system for managing students. I have several tables (Students, StudentAddresses, Grades, and Courses).
Here are problematic two tables:
1) Student table:
public Student()
{
this.Courses = new HashSet<Course>();
}
public int StudentId { get; set; }
[Required]
[StringLength(50, MinimumLength = 2, ErrorMessage = "The name must have over 2 and under 50 characters!")] // stavlja ograničenje na duljinu stringa u bazi
public string Name { get; set; }
[Required]
[StringLength(50, MinimumLength = 2, ErrorMessage = "The name must have over 2 and under 50 characters!")]
public string Surname { get; set; }
public int CurrentGradeId { get; set; }
public Grade CurrentGrade { get; set; }
public virtual StudentAdress Address { get; set; }
public virtual ICollection<Course> Courses { get; set; }
2) StudentAddress table:
public int StudentId { get; set; }
public string Address1 { get; set; }
public string Adress2 { get; set; }
public string City { get; set; }
public int ZipCode { get; set; }
public string Country { get; set; }
public virtual Student Student { get; set; }
In short, I'm trying to update StudentAddresses properties (to be more precise Address1 property for Student) while inside Student edit Action Method.
Here is View for Edit student:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Student</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.StudentId)
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Surname, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Surname, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Surname, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CurrentGradeId, "CurrentGradeId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CurrentGradeId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CurrentGradeId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Address.Address1, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Address.Address1, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Address.Address1, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
And finally here is Edit Action Method for StudentsController:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "StudentId,Name,Surname,CurrentGradeId")] Student student )
{
if (ModelState.IsValid)
{
// getting student id for current studentid
StudentAdress addresa = db.Addresses.Find(student.StudentId);
// trying to bind input value
addresa.Address1 = student.Address.Address1.ToString();
// saving new value in StudentAddresses field Address1
db.Entry(addresa).State = EntityState.Modified;
db.SaveChanges();
db.Entry(student).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CurrentGradeId = new SelectList(db.Grades, "GradeId", "GradeName", student.CurrentGradeId);
return View(student);
}
So, in Edit method, I want to save new input value for Address1 inside Edit method for Student table. Or to put it simpler, I want to update field Address1 in StudentAddress class while Editing Student class
UPDATE 1
So, let's say that I've figure it out but I'm still wondering if it is proper and right way of doing it.
In Student Edit action method I added addresa.Address1 = Request.Form["Address.Address1"]; where I updated field with attribute name=Address.Address1 and it did a trick but I'm wondering if it is right way of doing it?
Keep in mind that I've tried this
**addresa.Address1 = student.Address.Address1;**
but using this "cleaner" approach gave me:
System.NullReferenceException: Object reference not set to an instance
of an object.
Could I updated Address.Address1 field using some other approach?
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "StudentId,Name,Surname,CurrentGradeId")] Student student )
{
if (ModelState.IsValid)
{
StudentAdress addresa = db.Addresses.Find(student.StudentId);
// newly added line
addresa.Address1 = Request.Form["Address.Address1"];
db.Entry(addresa).State = EntityState.Modified;
db.SaveChanges();
db.Entry(student).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CurrentGradeId = new SelectList(db.Grades, "GradeId", "GradeName", student.CurrentGradeId);
return View(student);
}
Your relationships are wrong.
In your StudentAddress model we can see the StudentId foreign key which means relationship between Student and StudentAddress is one to many. But in your Student model you have virtual StudentAdress Address which should be ICollection<StudentAdress> Addresses.
And in your add/edit you could just do:
var student = context.Student.Find(1);
student.Addresses.Add(new StudentAdress {
Address1 = "Ul. Janka Leskovara",
City = "Pregrada",
ZipCode = 49218,
Country = "Hrvatska"
});
context.SaveChanges();

C# razorview DropDownListFor 'Value cannot be null'

I am new to ASP.NET MVC and I'm working on my first project just for fun.
I get this ArgumentNullException and I cannot figure out what's wrong.
This is my model:
public class SpeciesLabel
{
[Key]
[Required]
public string Name { get; set; }
[Required]
public CustomGroup CustomGroup { get; set; }
[Required]
public Family Family { get; set; }
[Required]
public Genus Genus { get; set; }
[Required]
public Species Species { get; set; }
}
public class SpeciesLabelDbContext : DbContext
{
public SpeciesLabelDbContext()
: base("DefaultConnection")
{
}
public DbSet<SpeciesLabel> SpeciesLabel { get; set; }
}
This is the controller:
public ActionResult Create()
{
List<SelectListItem> customGroups = new List<SelectListItem>();
IQueryable<string> customGroupsQuery = from g in customGroupsDb.CustomGroup
select g.Name;
foreach (var element in customGroupsQuery)
{
customGroups.Add(new SelectListItem()
{
Value = element,
Text = element
});
}
ViewBag.CustomGroup = customGroups;
This is the controller POST request:
public ActionResult Create([Bind(Include = "CustomGroup,Family,Genus,Species")] SpeciesLabel speciesLabel)
{
if (ModelState.IsValid)
{
db.SpeciesLabel.Add(speciesLabel);
db.SaveChanges();
return RedirectToAction("Create");
}
return View();
}
And this is the view:
<pre>
#model PlantM.Models.PlantModels.SpeciesLabel
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Species label</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.CustomGroup, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.CustomGroup, new SelectList(ViewBag.CustomGroupList, "Value", "Text"), "Please select...", new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CustomGroup, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
</pre>
I have inputs for all properties in the view but I cut them as they are similar to this one and the exception would be the same. Only property Name is not returned from the view as it will be designed in the controller (concatenation of the other properties).
This is the exception I get when I submit the form:
ArgumentNullException
Edit:
After adding the ViewBag initialization in the POST Create method the problem with the ArgumentNullException is resolved but I still receive Null value arguments and the object cannot be created due to this and the Create view is recalled again and again!? Can anyone advise why these #Html.DropDownListFor do not post any value to the controller?
From the comment, it sound like you see the view on first visit, but a null exception happen after you post.
If above assumption is correct, then I think your problem is because when you post back, your model did not pass the validation (for example, maybe a required input field did not post back value), which means ModelState.IsValid is false, so return View() was called
Here is the problem, you are not setting the ViewBag.CustomGroup = customGroups; in before return, hence ViewBag.CustomGroup is null, that is why you are seeing the exception.
init the ViewBag like how you did it on get then you should be able to see the page.

.NET MVC 5 Check Box list from database using View Model [duplicate]

This question already has answers here:
Pass List of Checkboxes into View and Pull out IEnumerable [duplicate]
(2 answers)
Closed 6 years ago.
I need to populate a checkbox list of equipment on a form for users to request equipment. The data for the list is stored in a table named 'Equipment'. I am working with EF 6 database first. The view is strongly typed and will write to an 'Orders' table. I am stuck on how to use a View Model and not ViewBag to populate the check box list for the form. I have looked at MikesDotNetting, the Rachel Lappel post about view models and several others and it's not making sense to me.
Code below:
public class Equipment
{
public int Id { get; set; }
public string Description { get; set; }
public string Method { get; set; }
public bool Checked { get; set; }
}
public class Order
{
public int id{ get; set; }
public string Contact_Name { get; set; }
public List<Equipment>Equipments { get; set; }
public string Notes { get; set; }
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Contact_Name,Equipment,Notes")] Order order)
{
if (ModelState.IsValid)
{
db.Orders.Add(order);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(order);
}
View
#model CheckBoxList.Models.Order
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Order</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Contact_Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Contact_Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Contact_Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
//checkbox list populated here
</div>
<div class="form-group">
#Html.LabelFor(model => model.Notes, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Notes, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Notes, "", new { #class = "text-danger" })
</div>
</div>
See this answer for how to do it How to bind checkbox values to a list of ints?
That example uses Guid's as PK's but that can be easily replaced with int's.
I'm going to assume your Equipment class is your EF entity.
So you are creating your order page so let's start with the CreateOrderViewModel
public class CreateOrderViewModel
{
public string Contact_Name { get; set; }
public Dictionary<int, string> AllEquipment{ get; set; }
public int[] SelectedEquipment { get;set; }
public string Notes { get; set; }
}
Populate AllEquipment with just the id and the name of the piece of equipment. This is the complete list of equipment that will be needed to show all the equipment checkboxes with the value of the id of the equipment.
Something like
var viewModel = new CreateOrderViewModel {
AllEquipment = context.Equipment.ToDictionary(e => e.Id, e.Description);
}
SelectedEquipment is the list of equipment with checkboxes checked. So when you post this information back, the SelectedEquipment property will have a list of all the id's that need to be attached to the order.
When you create the order just iterate through the list and add them to the Equipment list in your Order entity.
Make a for loop in your list and generate a checkbox for every item in it.
<div class="form-group">
#for (int i = 0; i < Model.Equipments.Count(); i++)
{
#Html.CheckBoxFor(x => x.Equipments[i].Checked)
#Model.Equipments[i].Description
//If you need to hide any values and get them in your post
#Html.HiddenFor(x => x.Equipments[i].Id)
#Html.HiddenFor(x => x.Equipments[i].Method)
}
</div>

Helper for DropDown List in ASP.NET MVC

I'm creating ASP.NET MVC application and I have problem with my dropdowns in "Register" page.
First, my model (Created by EF in "database first" mode):
public partial class User()
{
...
public int CountryId { get; set; }
}
public partial class Country()
{
...
public int Id { get; set; }
public String Name { get; set; }
}
NOTE: User and Country are related by CountryId (is not a collection)
In my controller:
ViewBag.countries = context.Countries.ToList();
return View();
In my view:
<select name="CountryId" id="CountryId">
#foreach (var item in ViewBag.countries)
{
<option value="#item.Id" id="#item.Id">#item.Name</option>
}
</select>
So, I think that I need use this helpers:
#Html.DropDownList
#Html.DropDownListFor
But it's imposible doing work...
The default code of ASP.NET for views is:
<div class="form-group">
#Html.LabelFor(model => model.CountryId, "CountryId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CountryId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CountryId, "", new { #class = "text-danger" })
</div>
</div>
And this code throws this error:
Additional information: There is no ViewData item of type 'IEnumerable' that has the key 'CountryId'.
Any suggestions? Thanks in advance!!

Categories