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:
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.
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.
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.
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.
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:
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.
Pretty damn simple. Do this:
Session["MyStringVariable"] = "Some value I want to keep around";
Session["MyIntegerVariable"] = 42;
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!).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With