Razor will not display hidden exact PC in HiddenFor

Running into a strange problem on my ASP MVC 4 site. If a user opens the create form and tries to add an agent to our database, we naturally run a check on the first fields. If there is an error, we save the agent in an incomplete state and redirect the user back to the creation page.

The error occurs when the user tries to save the agent again. At the first callback, the agent is stored in the database and PK is generated. However, on the second post-back side, the PC is sent to the server with a value of 0 instead of what was just generated automatically.

I added HiddenFor to the create view, however this displays a value of 0 each time.

I also went through the code to make sure that PK is generated after the .Save call is still present when the return View is called, and also ensures that the Model.ID property contains the same value when viewing the view.

Regardless, if I right-click on the page and look at the source, the hidden field will look like this:

 <input data-val="false" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="0" /> 

Model

 public partial class AgentTransmission { public int ID { get; set; } . . . } 

View

 @model MonetModelFromDb.Models.AgentTransmission @{ ViewBag.Title = "Create new Agent"; } @Html.HiddenFor(model => model.CreatedDate, new { data_val = "false" }) @Html.HiddenFor(model => model.CreatedOperator, new { data_val = "false" }) @Html.HiddenFor(model => model.ReferenceNumber, new { data_val = "false" }) @Html.HiddenFor(model => model.Region, new { data_val = "false" }) @Html.HiddenFor(model => model.INDDist, new { data_val = "false" }) @Html.HiddenFor(model => model.LastChangeDate, new { data_val = "false" }) @Html.HiddenFor(model => model.LastChangeOperator, new { data_val = "false" }) @Html.HiddenFor(model => model.EditTaxId, new { data_val = "false" }) @Html.HiddenFor(model => model.ParentId, new { data_val = "false" }) @Html.HiddenFor(model => model.IsSubstat, new { data_val = "false" }) @Html.HiddenFor(model => model.ID, new { data_val = "false" }) 

Drawn HiddenFor section

 <input data-val="false" data-val-date="The field CreatedDate must be a date." id="CreatedDate" name="CreatedDate" type="hidden" value="" /> <input data-val="false" id="CreatedOperator" name="CreatedOperator" type="hidden" value="" /> <input data-val="false" id="Region" name="Region" type="hidden" value="NM-834" /> <input data-val="false" id="INDDist" name="INDDist" type="hidden" value="834" /> <input data-val="false" data-val-date="The field LastChangeDate must be a date." data-val-required="The LastChangeDate field is required." id="LastChangeDate" name="LastChangeDate" type="hidden" value="4/8/2015 10:43:30 AM" /> <input data-val="false" id="LastChangeOperator" name="LastChangeOperator" type="hidden" value="TYPCLS" /> <input data-val="false" data-val-required="The EditTaxId field is required." id="EditTaxId" name="EditTaxId" type="hidden" value="False" /> <input data-val="false" data-val-number="The field ParentId must be a number." id="ParentId" name="ParentId" type="hidden" value="" /> <input data-val="false" data-val-required="The IsSubstat field is required." id="IsSubstat" name="IsSubstat" type="hidden" value="False" /> <input data-val="false" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="0" /> 

controller

  [HttpPost] [MonetAuthorize] public ActionResult Create(AgentTransmission agenttransmission, bool andAddAgent = false) { . . . //Determine if this is first POST or not if (agenttransmission.ID > 0) { db.Entry(agenttransmission).State = EntityState.Modified; } else { db.AgentTransmission.Add(agenttransmission); } db.SaveChanges(); //Send back to view if errors pressent if (!String.IsNullOrWhiteSpace(errorMsg)) { return View(agenttransmission); } } 

EDIT

If I remove the HiddenFor and just cut / paste the input tag, I can fix the PK value of the tuple. However, this is a bit hacky, so I was hoping to find a more elegant solution (if possible)

 <input data-val="false" id="ID" name="ID" type="hidden" value="@Model.ID" /> 
+5
source share
1 answer

Variations on this subject are often asked here. It basically comes down to the ModelState object and the fact that its values ​​override the values ​​for the real model to represent. When you submit the form, 0 set in the ModelState for your ID property. In post action, you save an object that causes its ID property to be updated, but 0 is still in ModelState . When you return the view, 0 again set as the value for the ID , because, again, that in ModelState .

The reason this works is best explained by example. Say you have a form in which you are editing an existing object that has the Name property set to "Foo". The user changes this on the form to β€œBar,” and then publishes the form. However, they neglected filling in the required field, so the error prevents their updating. What should happen at this moment? If we use the model value, the Name field will reset to "Foo". However, if ModelState used, the Name field retains the custom modification of Bar. In the latter case, they simply correct the error and publish again. In the first, they should redo all the changes that they made to the form earlier, which, obviously, will be a very bad user interface.

Now how to fix it. The best way is to follow the PRG (Post-Redirect-Get) pattern. If the view is good and you successfully saved the changes, do not revert the view, even if you want the user to be able to make additional changes immediately. If you want this, just redirect back to the same action, but the redirect process is enough to clear ModelState so that the user now interacts with the updated model retrieved from the database.

If this is not feasible, you can simply clear ModelState . I would advise you not to clean it completely, as you can cause very real user frustration, as described in the example above. If you really can't do the redirection, just try to clear the values ​​in ModelState that you really need.

 ModelState.Remove("ID"); 
+6
source

All Articles