Search code examples
c#tempdataasp.net-core-5.0

How to add a ViewModel Object to TempData


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

enter image description here

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?


Solution

  • 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.