I have a page where some values are posted to my controller as part of a view model. The controller attempts to process a list within the controller and will spit back any values it couldn't process.
Now first time the page loads everything is good, however when the user posts any tokens that are incorrect then Razor or ASP.NET messes with the data going out.
So if the user sends in:
Token1 = ABC
Token2 = DEF
Token3 = GHI
And token 1 and 3 fail then the model that is passed back is:
Token1 = ABC
Token3 = GHI
But what gets rendered is:
Token1 = ABC
Token3 = DEF
I have verified that I am passing the correct data back as next to the textbox I have told it to just output the keycode (ie: "GHI" from above) and it does as text render the correct value, but in the textbox next to it, referencing the same variable (Model.Tokens[tokenCounter].KeyCode) it gets rendered incorrectly.
Code in the controller:
if (failedTokens.Count == 0)
{
// Forward to success page
...
}
else
{
ModelState.AddModelError("", "Tokens couldn't be added");
bulkTokenCreateModel.Tokens = failedTokens;
return View(..., bulkTokenCreateModel);
}
Code in the view:
@for (var tokenCounter = 0; tokenCounter < Model.Tokens.Count; tokenCounter++)
{
...
<td>
<div class="form-group">
@Model.Tokens[tokenCounter].KeyCode
@Html.TextBoxFor(model => Model.Tokens[tokenCounter].KeyCode, new { @class = "form-control" })
</div>
</td>
...
}
I can only put this down to ASP.NET or Razor messing with model? Or am I missing something stupid? Any thoughts, or anything to check would be very helpful
EDIT:
Have been asked to add classes:
public class BulkTokenCreateModel
{
public string Notes { get; set; }
public int Quantity { get; set; }
public List<Token> Tokens { get; set; }
}
public class Token
{
public int FobId { get; set; }
public DateTime DateAdded { get; set; }
public string KeyCode { get; set; }
...
}
The token class is not a strictly ViewModel only class (while the BulkTokenCreateModel class is), but the KeyCode property in question is only a simple string property. I have removed the other parts of the class for fear of giving too much away about the inner workings of the software. If need be I can post more, but nothing in that class interferes with the KeyCode property.
EDIT2:
Was asked for the full code in the action of the controller so here goes:
public ActionResult ScanTokensComplete(BulkTokenCreateModel bulkTokenCreateModel)
{
var businessLayer = BusinessLayerManager.Current;
var failedTokens = new List<Token>();
foreach (var token in bulkTokenCreateModel.Tokens)
{
try
{
token.DateAdded = DateTime.Now;
token.Enabled = true;
var addedToken = businessLayer.TokenAdd(token);
}
catch (FaultException<ArgumentNullFault> detail)
{
failedTokens.Add(token);
ModelState.AddModelError("KeyCode", detail.Detail.Message + $" : Token : { token.KeyCode }");
}
catch (Exception ex)
{
failedTokens.Add(token);
ModelState.AddModelError("KeyCode", ex.Message + $" : Token : { token.KeyCode }");
}
}
if (failedTokens.Count == 0)
{
SearchCache.UpdateCache(typeof(Token), User.BrowsingClientId);
return RedirectToAction(...);
}
else
{
ModelState.AddModelError("", "Tokens couldn't be added");
bulkTokenCreateModel.Tokens = failedTokens;
return View(..., bulkTokenCreateModel);
}
}