Why DefaultModelBinder doesn't bind route value ID from URL - asp.net-mvc

ASP.NET MVC
In short:
I have a get action and a post action
when I type in browser localhost:port/Employee/Edit/1 I call get action, so in URL I have this whole url string. When I press submit button, in post action defaultmodelbinder doesnt bind id from URL!!!! I HAVE TO ADD HIDDEN FIELD for id. But why? I also have delete action (post), that gets id too, and I dont need to add hidden field for id. why?
More specifically:
I have the model:
public class EmployeeViewModel
{
public Int32 EmployeeId { get; set; }
public String Name { get; set; }
public String Phone { get; set; }
public String Email { get; set; }
public String Other { get; set; }
}
And 2 actions
public ActionResult Edit(int id)
{
try
{
EmployeeViewModel model;
using (var dbSession = NHibernateHelper.OpenSession())
{
var employee = dbSession.Query<Employee>().First(e => e.EmployeeId == id && e.ExpireDate==null);
model = new EmployeeViewModel(employee);
}
return View(model);
}
catch
{
return View("Error");
}
}
[HttpPost]
public ActionResult Edit(EmployeeViewModel model)
{
try
{
using (var dbSession=NHibernateHelper.OpenSession())
using (var transaction=dbSession.BeginTransaction())
{
var employee = model.ToEmployee();
dbSession.Merge(employee);
transaction.Commit();
}
return RedirectToAction("Index");
}
catch
{
return View("Error");
}
}
And 1 View (HERE I HAVE TO WRITE THIS LINE #Html.HiddenFor(model => model.EmployeeId) )
#using (Html.BeginForm()){
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.HiddenFor(model => model.EmployeeId)
#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.Phone, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Phone, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Phone, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Email, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Email, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Other, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Other, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Other, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Сохранить" class="btn btn-default" />
</div>
</div>
</div>}

Because the parameter in the method is named id and the property in
your model is named EmployeeId They are not the same. And if you
change the model property to Id it will be bound
Thanks, Stephen Muecke

Related

The model item passed into the dictionary is of type 'System.Collections.Generic.List but this dictionary requires a model item of type 'XXX.XXX.XXX'

I am trying to use strongly typed dropdownlist for my application. I have textbox fields as well. But when i pass #model Aayumitra.Models.RegisterViewModel
#using Aayumitra.Models; I am getting below error.
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[System.Web.Mvc.SelectListItem]', but this dictionary requires a model item of type 'XXX.XXX.XXX'.
AccountViewModel
public class RegisterViewModel
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public IEnumerable<SelectListItem> Genders { get; set; }
}
Controller
private static List<SelectListItem> GetGenders()
{
AayumitraDBEntities db = new AayumitraDBEntities();
List<SelectListItem> GenderList = (from p in db.Genders.AsEnumerable()
select new SelectListItem
{
Text = p.GenderType,
Value = p.GenderId.ToString()
}).ToList();
//Add Default Item at First Position.
GenderList.Insert(0, new SelectListItem { Text = "--Select Gender--", Value = "" });
return GenderList;
}
//
// GET: /Account/UpdatePatient
[AllowAnonymous]
public ActionResult UpdatePatient()
{
List<SelectListItem> GenderList = GetGenders();
return View(GenderList);
}
View
#model Aayumitra.Models.RegisterViewModel
#using Aayumitra.Models;
#using (Html.BeginForm())
{
<div class="row">
<div class="col-md-4">
<div class="profile-container">
<div class="profile">
<img src="~/Content/images/logo.png" width="100" />
</div>
<div class="profile-info">
<p>
#Html.TextBox("FullName", User.Identity.Name.ToString(), new { #readonly = "readonly", #disabled = "disabled" })
</p>
</div>
</div>
</div>
</div>
<div class="dropdown-divider"></div>
<div class="row">
<div class="col-sm-3">
<div class="form-group">
#Html.LabelFor(model => model.FirstName, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-sm-3">
<div class="form-group">
#Html.LabelFor(model => model.MiddleName, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.MiddleName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.MiddleName, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-sm-3">
<div class="form-group">
#Html.LabelFor(model => model.LastName, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.LastName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.LastName, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-sm-3">
<div class="form-group">
#Html.LabelFor(model => model.Gender, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownListFor(x => Model.Gender, new SelectList(Model.Genders, "Value", "Text"), htmlAttributes: new { #class = "form-control", id = "Gender" })
</div>
</div>
</div>
}
if your View is supposed to be for UpdatePatient, then you want to create a model of type RegisterViewModel and add Genders to it, and then pass that model to the View, like this:
public ActionResult UpdatePatient()
{
List<SelectListItem> GenderList = GetGenders();
return View(new RegisterViewModel
{
FirstName = "",
MiddleName = "middle",
LastName = "last",
Genres = GenderList
});
}

POST form in MVC - No Values being written to DB

I have a model that I'm trying to edit with a form:
public class Basiclife
{
[Key]
public int Id { get; set; }
public int? ResponseId { get; set; }
public string Plantype { get; set; }
public int Enrolledftes { get; set; }
public decimal Pctemployer { get; set; }
public decimal Fixedbenamt { get; set; }
public decimal Salarymult { get; set; }
public decimal Bencap { get; set; }
}
And a view wrapper to edit it (with the editor in a separate partial view):
<h2>CreateBasicLifeResponse</h2>
<div id="planList">
#using (Html.BeginForm("CreateBasicLifeResponse", "Surveys"))
{
<div id="editorRows">
#foreach (var item in Model.basiclives)
{
#Html.Partial("_BasicLifeResponse", item)
}
</div>
#Html.ActionLink("Add", "BasicLifeResponse", null, new { id = "addItem", #class = "button" });
<input type="submit" value="submit" />
}
</div>
The wrapper's model is:
public class ResponseBasicLife
{
public Response response { get; set; }
public List<Basiclife> basiclives { get; set; }
}
Here's the partial view:
#using CustomSurveyTool.Models
#model Basiclife
<div class="editorRow">
#using (Html.BeginCollectionItem("basiclives"))
{
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Plantype, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Plantype, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Plantype, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Enrolledftes, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Enrolledftes, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Enrolledftes, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Pctemployer, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Pctemployer, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Pctemployer, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Fixedbenamt, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Fixedbenamt, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Fixedbenamt, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Salarymult, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Salarymult, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Salarymult, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Bencap, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Bencap, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Bencap, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
X
</div>
</div>
}
</div>
Here's my controller action where I'm getting the proper responseId and assigning it to the form values:
public ActionResult CreateBasicLifeResponse(ResponseBasicLife model)
{
for (var i = 1; i < model.basiclives.Count; i++)
{
string currentUserId = User.Identity.GetUserId();
Response targetresponse = db.response.FirstOrDefault(x => x.Userid == currentUserId);
int responseid = targetresponse.Id;
model.basiclives[i].ResponseId = responseid;
db.basiclife.Add(model.basiclives[i]);
db.SaveChanges();
}
ResponseBasicLife basicliferesponse = new ResponseBasicLife
{
basiclives = new List<Basiclife>
{
new Basiclife { }
}
};
return View(basicliferesponse);
}
The only thing that's being written to the database is the ResponseID. How do I get the rest of the values to write to it?
This is a unique case where EditorFor could help. Essentially an object will have its editor template which is kind of like a partial view but specific to editing forms.
Secondly, the being form you are specifying is expecting the model of the view that you specified - in your case the viewWrapper. If for instance you specified a List<BasicLife>, then that is what the postBack shall be expecting, and not the BasicLife object. Below is how your postback would look like.
[HttpPost]
public ActionResult CreateBasicLifeResponse(List<BasicLife> model){
//your code goes here
}
From your view though, it looks clear that Model contains more than just a list. That is what shall be expected from the callback.

Cannot save values from form to database

I am trying to write my first ASP.NET MVC application with Entity Framework (code first).
I am trying to insert data from form to specific table in database but it does not work. When I press "Submit" button, page is refreshing but table still has not any value. There is no error on page or in console.
Could you please take a look on code and help me ?
Below is my code:
View:
#model VeterinaryApp.Models.Clients
#{
ViewBag.Title = "AddClient";
Layout = "~/Views/SharedViews/_MainLayout.cshtml";
}
<h2>AddClient</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Clients</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<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.Email, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Email, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Phone, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Phone, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Phone, "", 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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Controller:
public class AddClientController : Controller
{
// GET: AddClient
public ActionResult AddClient()
{
return View();
}
//POST
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ClientsId, Name, Surname, Email, Phone")] Clients clients)
{
if (ModelState.IsValid)
{
using (StoreContext db = new StoreContext()) //DbContext
{
db.Clients.Add(clients);
db.SaveChanges();
return RedirectToAction("Index");
}
}
return View(clients);
}
}
Model
public class Clients
{
public int ClientsId { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public int Phone { get; set; }
public virtual ICollection<BookVisit> BookedVisits { get; set; }
public virtual ICollection<Animals> OwnedAnimals { get; set; }
}

The current request for action ... on controller type ... is ambiguous between the following action methods

When I run the application on browser with ~/Person/New the result is
The current request for action 'New' on controller type 'PersonController' is ambiguous between the following action method System.Web.Mvc.ActionResult New() on type PersonMVC.Controllers.PersonController System.Web.Mvc.ActionResult New(PersonMVC.Models.Person) on type PersonMVC.Controllers.PersonController
Model
namespace PersonMVC.Models
{
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
[Required]
[DisplayName("Social Sequrity Number")]
[MinLength(11, ErrorMessage ="Social Security Number Must be 11 digit.")]
[MaxLength(11, ErrorMessage ="")]
public string SocialSecurityNumber { get; set; }
[DisplayFormat(DataFormatString ="{0:dd.MM.yyyy}")]
public DateTime BirthDay { get; set; }
}
}
-View
#model PersonMVC.Models.Person
#{
ViewBag.Title = "New";
}
<h2>New</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Person</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<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.LastName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.LastName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.LastName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SocialSecurityNumber, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SocialSecurityNumber, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SocialSecurityNumber, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.BirthDay, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.BirthDay, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.BirthDay, "", 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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Controller
namespace PersonMVC.Controllers
{
public class PersonController : Controller
{
public ActionResult New()
{
return View();
}
[HttpPost]
public ActionResult New(Person newPerson)
{
bool isTrue = ModelState.IsValid;
return View();
}
}
}
you need to decorate the method with appropriate http verb. Otherwise it will be considered as HttpPost usually.
i think adding [HttpPost] to the controller method would solve the problem

Don't fire a required validator for

I have the following model:
public class Model1
{
[Required(ErrorMessage="E1")]
public string Name { get; set; }
[Required(ErrorMessage="E2")]
[RegularExpression(".+\\#.+\\..+")]
public string Email { get; set; }
[Required(ErrorMessage="E3")]
public bool WillAttend { get; set; }
}
controller action:
public ActionResult Model1()
{
Model1 m = new Model1();
return View(m);
}
and view:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Model1</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<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.Email, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Email, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.WillAttend, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.WillAttend)
#Html.ValidationMessageFor(model => model.WillAttend, "", new { #class = "text-danger" })
</div>
</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>
}
problem is required validator for WillAttend property does not work. Even in action method, ModelState.IsValid is true. Why and how to do WillAttend is required ?
At the moment, your required-attribute just checks whether a value was specified. Since a boolean is either true or false, the validation will never fail.
You can, mark the boolean as nullable:
public bool? WillAttend { get; set; }
or you can try to make a custom validator if you are trying to force them to check the box, such as in this link.

Resources