Search code examples
http-redirectmodel-view-controllertempdata

Why is TempData[] NULL after RedirectToAction in MVC


Problem: I set TempData in my Post action then redirect to my Index action. TempData is not NULL in the post after I set it but is NULL in the Index action.

I've been searching threads to find an answer to this and everything I see says that the following should work, but alas, it does not.

Can anybody see what is wrong here?

[HttpGet]
        public async Task<IActionResult> Index()
        {
            //var lCARContext = _context.TblRules.Include(t => t.Agency).Include(t => t.Department);
            //return View(await lCARContext.ToListAsync());

            var rulevm = new RulesViewModel();
> TempData is NULL at this point.
            var actionConfirmation = TempData["ActionConfirmation"];
            TempData["ActionConfirmation"] = actionConfirmation;
            return View(rulevm);
        }

[HttpPost]
public async Task<IActionResult> Edit(string id, 
            [Bind("...")]
            TblRules tblRules, string NewProposedRuleNo)
        {
            if (id != tblRules.ProposedRuleNo)
            {
                return NotFound();
            }

            if (!tblRules.AgencyId.HasValue & !tblRules.DepartmentId.HasValue)
            {

                ModelState.AddModelError(string.Empty, "Select an Agency and/or Department for this rule.");
                // set the property level messages
                ModelState["AgencyId"].Errors.Add("Need either an Agency or Department specified.");
                ModelState["DepartmentId"].Errors.Add("Need either an Agency or Department specified.");
            }

            if (ModelState.IsValid)
            {
                try
                {
                    // first save any changes other than the rule number that the user
                    // has made.
                    _context.Update(tblRules);
                    await _context.SaveChangesAsync();

                    // Now if user changed the proposed rule number change it.
                    // Needs to be done outside of EF since EF does not support changing the PK.
                    if (NewProposedRuleNo != null)
                    {
                        _context.ChangeProposedRuleNumber(tblRules.ProposedRuleNo, NewProposedRuleNo);
                    }
                    // Return results of the action
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    if (!TblRulesExists(tblRules.ProposedRuleNo))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                TempData["ActionConfirmation"] = "Processing successful.";
> TempData is Not NULL at this point.
                return RedirectToAction("Index");
                //return RedirectToAction(nameof(Index));
            }
            // following executed if model is not valid
            ViewData["AgencyId"] = new SelectList(_context.TblAgencies.Where(wh => wh.AgencyOrBoard != null).OrderBy(ob => ob.AgencyOrBoard), "AgencyId", "AgencyOrBoard", tblRules.AgencyId);
            ViewData["DepartmentId"] = new SelectList(_context.TblDepartments.Where(wh => wh.DeptOrDivision != null).OrderBy(ob => ob.DeptOrDivision), "DepartmentId", "DeptOrDivision", tblRules.DepartmentId);
            ViewData["RuleType"] = new SelectList(_context.TlkpRuleTypes.OrderBy(ob => ob.RuleType), "RuleType", "RuleType", tblRules.RuleType);
            ViewData["Attorneys"] = new SelectList(_context.TblAttorneys.OrderBy(ob => ob.AttorneyName), "AttorneyName", "AttorneyName", null);
            ViewData["CurrentAttorneys"] = new SelectList(tblRules.TblReceivingAttorneys.OrderBy(ob => ob.AttorneyName), "AttorneyName", "AttorneyName", null);
            ViewData["CommitteesOfJurisdiction"] = new SelectList(_context.TblCommittees.OrderBy(ob => ob.CommitteName), "CommitteName", "CommitteName", null);
            ViewData["CurrentCommitteesOfJurisdiction"] = new SelectList(tblRules.TblCommitteesOfJurisdiction.OrderBy(ob => ob.CommitteName), "CommitteName", "CommitteName", null);
            ViewData["Actions"] = new SelectList(_context.TlkpActionsTaken.OrderBy(ob => ob.ActionDescription), "ActionDescription", "ActionDescription", null);
            ViewData["CurrentActions"] = new SelectList(tblRules.TblActions.OrderBy(ob => ob.ActionDescription), "ActionId", "ActionDescription", null);
            // Return the rules edit view model.
            var vm = tblRules.ToCreateRulesEditViewModel();
            // Return results of the action
            TempData["ActionConfirmation"] = "Validations failed.";
> TempData is Not NULL at this point AND is displayed on the view
            vm.AgencyContact = ViewModelExtensionMethods.FormatAgencyContactInformation(tblRules.Agency, true, true);
            return View(vm);
        }

_Layout.cshtml that displays the TempData on Validation error but not the Success value

<div>
    @if (TempData["ActionConfirmation"] != null)
    {
        <p>@TempData["ActionConfirmation"]</p>
    }
    </div>

Index.cshtml that shows the TempData for validation errors but not for success

<div>
    @if (TempData["ActionConfirmation"] != null)
    {
        <p>@TempData["ActionConfirmation"]</p>
    }
</div>

Solution

  • I found the solution. Apparently in Startup.Configure I needed to have the app.UserCookiePolicy() after the app.UseMVC(). Making this change allowed the Tempdata to remain intact across the redirect.

    This page provided me with the hint that solved my problem. I relied on hmdhasani's original message and not the example from further down, which still had the app.UserCookiePolicy first.

            app.UseMvc(routes =>
            {
                //routes.MapRoute(
                routes.MapRoute(
                    name: "default",
                    template: "{controller=TblRules}/{action=Index}/{id?}");
            });
    
            app.UseCookiePolicy();
    

    Hope this post helps someone else.