My model is not passing back to the controller on post. I'm doing this in another part of the application and it works fine. I have probably missed something but I have been over this for two days and I can't see it. I hope you can assist.
My View:
@model Towins.Models.T_Complaints
@{
ViewBag.Title = "UpsertComplaint";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm("UpsertComplaint_Post", "Home", FormMethod.Post))
{
@Html.AntiForgeryToken()
// The model is working on the get.
// The date has been supplied in the get and I have it in the view.
// The Model.Id == 0 as this is the add portion of the upsert.
// Can't even start working on the update portion as the model is not coming back at all.
<h4>@(Model.Id!=0 ? "Edit" : "Add") Complaint</h4>
<hr />
@Html.HiddenFor(model => model.Id)
@Html.HiddenFor(model => model.WreckerID)
<div style="text-align: center">
<div >
<div >
<label for="NewWrecker" >Wrecker Company Name</label>
<input type="text" disabled id="WreckerCo" name="WreckerCo" value="@ViewBag.WreckerCo" />
</div>
</div>
<div >
<div id="DateOfComplaint-group" data-date-format="dd/mm/yyyy">
<label for="ComplaintDate" >Complaint Date: </label>
@Html.EditorFor(model => model.ComplaintDate, "{0:mm/dd/yyyy}", new { htmlAttributes = new { @class = "form-control" } })
<span ><i ></i></span>
</div>
</div>
// Model Fields deleted for brevity
<div >
<div >
<div >
<input type="submit" name="NewComplaint" value="Save" />
</div>
<div >
<a href="@Url.Action("ComplaintList", new { wId = ViewBag.WreckerId })" >Back to Complaints List</a>
</div>
</div>
</div>
</div>
}
My Controller: This is posting properly but the model is null
[HttpPost]
public ActionResult UpsertComplaint_Post(T_Complaints complaint)
{
// complaint is null here.
// This is as far as I have gotten. I can't copmplete the post code until I
// can get the model back to this point.
return RedirectToAction("ComplaintList", new RouteValueDictionary(new { wId = complaint.WreckerID }));
}
And just for completeness, here is the model:
public class T_Complaints
{
public int Id { get; set; }
[DataType(DataType.MultilineText)]
public string Complaint { get; set; }
[DataType(DataType.MultilineText)]
[Display(Name = "Complainant Info")]
public string ComplainantInfo { get; set; }
[Required]
public int WreckerID { get; set; }
[Required]
public bool Resolved { get; set; }
[Required]
[DataType(DataType.Date)]
[Display(Name = "Complainant Date")]
public DateTime ComplaintDate { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Resolution Date")]
public DateTime ResolutionDate { get; set; }
[DataType(DataType.MultilineText)]
public string Resolution { get; set; }
}
Here is the Get Action
[HttpGet]
public ActionResult UpsertComplaint(int? cid, string WreckerCo, int wId)
{
T_Complaints complaint = new T_Complaints();
ViewBag.WreckerCo = WreckerCo;
ViewBag.wId = wId;
if (cid == null)
// This is true so this is the block that executes on Add
{
complaint.ComplaintDate = DateTime.Now;
complaint.WreckerID = wId;
return View(complaint);
}
using (con)
{
con.Open();
using (SqlCommand cmd = new SqlCommand("SELECT * FROM [Towins].[dbo].[T_Complaints] WHERE Id = " cid, con))
{
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
complaint.Resolved = (bool)reader["Resolved"];
complaint.Id = (int)reader["Id"];
complaint.Complaint = reader["Complaint"].ToString();
ViewBag.WreckerId = reader["WreckerID"];
complaint.ComplainantInfo = reader["ComplainantInfo"].ToString();
complaint.ComplaintDate = (DateTime)reader["ComplaintDate"];
if (reader["ResolutionDate"].ToString() != "")
{
complaint.ResolutionDate = (DateTime)reader["ResolutionDate"];
}
complaint.Resolution = reader["Resolution"].ToString();
};
}
reader.Close();
}
con.Close();
}
return View(complaint);
}
Okay. I've gotten some downgrades for insufficient research and not posting the question properly. I'm going to reattempt to get this question answered. I have simplified everything with test code and reposted it here:
My new test model in it's entirety:
namespace Towins.Models
{
public class T_ComplaintsTest
{
public int Id { get; set; }
public string Complaint { get; set; }
}
}
My new test View in its entirety:
@model Towins.Models.T_ComplaintsTest
@{
ViewBag.Title = "AddComplaint";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Add Complaint</h2>
@using (Html.BeginForm("AddComplaint", "Home", FormMethod.Post))
{
<div style="text-align: center">
<div >
<div >
@Html.LabelFor(model => model.Complaint)
@Html.EditorFor(model => model.Complaint, new { htmlAttributes = new { @class = "form-control" } })
</div>
</div>
<div >
<div >
<div >
<input type="submit" name="AddComplaint" value="Save" />
</div>
</div>
</div>
</div>
}
And, my action methods in their entirety:
[HttpGet]
public ActionResult AddComplaint()
{
T_ComplaintsTest complaint = new T_ComplaintsTest();
complaint.Complaint = "Test";
return View(complaint);
}
[HttpPost]
public ActionResult AddComplaint(T_ComplaintsTest complaint)
{
//Breakpoint here. Why is complaint null?
return RedirectToAction("ComplaintList", new RouteValueDictionary(new { wId = 247 }));
}
When the Get occurs, it successfully renders "Test" in the field. When I hit the submit button, it stops at the breakpoint "return RedirectToAction..." Why at this point is complaint null? I can see no reason for the life of me why it should be null. The view is of this Model. Should it not be there?
CodePudding user response:
The answer is simply that the model binder is getting confused.
Inside your T_Complaints
class, you have a property called Complaint
.
In your post action, you used complaint as the model name:
public ActionResult AddComplaint(T_ComplaintsTest complaint)
Simply changing the model name in the controller will make things less complicated for the model binder and your model won't be null.
public ActionResult AddComplaint(T_ComplaintsTest complaintsTest) // this won't be null anymore.