I have the following controller with a view model as follows -
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Initiate(IFormCollection formCollection)
{
var studentId = formCollection["studentid"].ToString();
if (string.IsNullOrEmpty(studentId))
{
return NotFound(new { msg = "Unknown student" });
}
Student student = await _context.Students.Include(s=>s.Parents).FirstOrDefaultAsync(s=>s.Id==studentId).ConfigureAwait(false);
var dashboard = User.FindFirstValue(ClaimTypes.Role).ToLower();
if (formCollection["bill"].Count > 0)
{
//Calculate the total bills and present a payment confirmation page
List<int> billIds = new List<int>();
foreach (var id in formCollection["bill"])
{
billIds.Add(Convert.ToInt32(id));
}
if (billIds.Count > 0)
{
List<Fee> fees = await _context.Fees.Where(f => billIds.Contains(f.Id)).ToListAsync().ConfigureAwait(false);
string CustomerEmail = null;
string CustomerPhone = null;
string CustomerFirstName = null;
string CustomerLastName = null;
if (student.Parents.Any())
{
var parent = student.Parents.FirstOrDefault();
CustomerEmail = parent?.Email;
CustomerPhone = parent?.PhoneNumber;
CustomerFirstName = parent?.OtherNames;
CustomerLastName = parent?.Surname;
}
string TrxnRef = RandomStringGenerator.UpperAlphaNumeric(5) + student.Id.Substring(0,8);
BillsPayViewModel model = new BillsPayViewModel
{
StudentId=student.Id,
StudentName=student.FullName,
PaymentItems=fees,
TransactionRef= TrxnRef,
CustomerPhone = CustomerPhone ?? student.PhoneNumber,
CustomerEmail = CustomerEmail ?? student.Email,
CustomerFirstname = CustomerFirstName ?? student.OtherNames,
CustomerLastname = CustomerLastName ?? student.Surname,
CustomerFullname=$"{CustomerFirstName} {CustomerLastName}",
Currency = "NGN",
AmountToPay=fees.Sum(a=>a.Amount),
Callbackurl=$"/Payments/Status/{TrxnRef}"
};
TempData["PaymentDetails"] = model;
return View("BillsPayConfirmation", model);
}
}
else
{
TempData["msg"] = "<div class='alert alert-success'><i class='fa fa-check'></i> No outstanding bills found for student</div>";
return RedirectToAction(dashboard, "dashboard");
}
return RedirectToAction();
}
I realize that the moment I add the part that adds the model to Temp Data
TempData["PaymentDetails"] = model;
I get the following
Is there a way to add the entire model to TempData
so I do not need to repeat the process of generating the ViewModel on the next page?
After much struggle, I came across this SO question that gave me a clue to what the issue is and it turns out that the problem is that TempData in ASP.NET Core (probably from version 5, because I have not tried this in other versions) does not have the capability to contain an object.
I was trying to add an object to TempData and that was the source of the problem. And the solution is to first serialize the model before adding it to TempData and then deserialize it back to the object where I need to use it as follows
TempData["PaymentDetails"] = JsonConvert.SerializeObject(model);
and at the point where I need it, deserialize it back as follows
BillsPayViewModel paymentDetails = JsonConvert.DeserializeObject<BillsPayViewModel>((string)TempData["PaymentDetails"]);
I guess this will save someone lots of time.