Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my Session["value"] not persisting across views (asp.net mvc)

I am electing to do session to store a value that I will need to call and update throughout a handful of controllers and views. I know it is possible to do something like this with a BaseViewModel.cs, or something less session-y, but I am trying to see how Session can possibly solve my needs. That out of the way, here is what I am doing:

Flow

I have a partial view that is rendered on my _layout page like so:

@Html.Action("OrgSwitch", new { controller = "Common", area = "InkScroll" })

This is a drop down list containing a logged in users organizations. It hits a CommonController that takes care of things like rendering model-bound logic on layout pages. In the CommonController I have this view and a postback, like so:

[ChildActionOnly]
    public ViewResult OrgSwitch()
    {
        var userOrgs = new List<SelectListItem>();
        var user = Ctx.Users.FirstOrDefault(x => x.UserName == User.Identity.Name);
        int key = 0;
        if (user.Organizations.Count > 0)
        {
            TempData["HasOrgs"] = true;
            foreach (var org in user.Organizations)
            {
                if (Session["SelectedOrgKey"] == null)
                {
                    //currently setting selected by primary org id
                    //todo: set selected to tempdata selectedOrgId if there is one.
                    userOrgs.Add(org.OrganizationId.ToString() == user.PrimaryOrgId
                        ? new SelectListItem { Text = org.Name, Value = org.OrganizationId.ToString(), Selected = true }
                        : new SelectListItem { Text = org.Name, Value = org.OrganizationId.ToString(), Selected = false });
                }
                else
                {
                    key = Convert.ToInt32(Session["SelectedOrgKey"]);
                    userOrgs.Add(org.OrganizationId == key
                        ? new SelectListItem { Text = org.Name, Value = org.OrganizationId.ToString(), Selected = true }
                        : new SelectListItem { Text = org.Name, Value = org.OrganizationId.ToString(), Selected = false });
                }
            }

            ViewBag.UserOrgs = userOrgs.OrderBy(x => x.Text);
        }
        else
        {
            ViewBag.UserOrgs = userOrgs;
            TempData["HasOrgs"] = false;
        }
        Session["SelectedOrgKey"] = key;
        return View();
    }

    [HttpPost]
    public RedirectToRouteResult OrgSwitch(string UserOrgs)
    {
        Session["SelectedOrgKey"] = UserOrgs;
        return RedirectToAction("Index", "Recruiter", new { orgId = UserOrgs, area = "InkScroll" });
    }

This more or less on initial load will render the drop down list and default it to the users primary org. If they select something and post back that selection, it will display the selected one by default on subsequent pages.

attempt and failure

I am trying various ways of utilizing the Session value. One area in a viewresult:

 [ChildActionOnly]
    public ViewResult StaffList()
    {
        var user = Ctx.Users.FirstOrDefault(x => x.UserName == User.Identity.Name);

        var model = new List<StaffListViewModel>();
        int key = Convert.ToInt32(Session["SelectedOrgKey"]);
        var org = user.Organizations.FirstOrDefault(x => x.OrganizationId == key);
        if (org.RegisteredMembers != null)
        {
            foreach (var req in org.RegisteredMembers)
            {
                model.Add(new StaffListViewModel
                {
                    UserName = req.UserName,
                    Name = (req.FirstName ?? "") + " " + (req.LastName ?? ""),
                    ImageLocation = req.ImageLocation
                });
            }
        }
        Session["SelectedOrgKey"] = key;
        return View(model);
    }

in here 'key' is coming up empty.

Another try is putting it in the layout cshtml file like so:

<li><a href="@Url.Action("Staff", "Recruiter", new {area="", 
                orgId = Convert.ToInt32(Session["SelectedOrgId"])})">Staff</a></li>

in this one if I hover over the link, the orgId is always equal to 0. Am I messing this up somewhere? Really, I need to have this SelectedOrgId available to any page on the application.

like image 534
ledgeJumper Avatar asked Mar 05 '14 16:03

ledgeJumper


People also ask

How long do session variables last ASP Net?

A session automatically ends if a user has not requested or refreshed a page in an application for a specified period of time. This value is 20 minutes by default. You can change the default for an application by setting the Session.

How do we maintain Sessions state in MVC?

ASP.NET MVC provides three ways (TempData, ViewData and ViewBag) to manage session, apart from that we can use session variable, hidden fields and HTML controls for the same.


1 Answers

An answer for posterity sake:

The code in the question DOES work. The way I am setting and calling session in asp.net mvc works fine. If you have arrived here in a vain search to get session working, then keep looking I guess. The issue I was have related to my control flow and the parameter i was passing in. Once I removed the 'orgId' from the parameters above, I refactored the if/else stuff to just look at session. So the issue was that somewhere in the app I am working on, orgId was not being changed from '0'. Anyway, I am an idiot, but at least I can give you a quick overview of what the hell Session is in asp.net mvc and how easy it is to use:

Setting up app to use session

Session is defaulted to be in process with a timeout of 20 minutes. If you feel like something is overwriting that default you can set it explicitly in your web.config (root web.config on a standard asp.net mvc app):

 <system.web>
    <sessionState mode="InProc" timeout="60"></sessionState>
    ...other stuff..
</system.web>

I set my timeout above to 60 minutes since I wanted it to stay around a little longer. Standard is 20.

Setting a session variable

Pretty damn simple. Do this:

Session["MyStringVariable"] = "Some value I want to keep around";
Session["MyIntegerVariable"] = 42;

Retrieving the session variable

again, pretty simple, you just need to pay attention to casting/converting the variable to what suits you.

var localVar = Session["MyStringVariable"].ToString();
var anotherLocalVar = Convert.ToInt32(Session["MyIntegerVariable"] = 42);

So, yeah, I was doing it right, but due to other complexities in my code above, I blamed the big bad Session and not my brain.

Hope this helps someone! (And if I have the above info wrong, please let me know and I will update!).

like image 177
ledgeJumper Avatar answered Sep 22 '22 01:09

ledgeJumper