0

I'm having a pretty tough time with this issue. I've done a lot of research but haven't found anything that works!

What I want to do: I want to use javascript to capture the user's timezone and utc timezone offset, store these two pieces of data in the browsers session, and then retrieve them in the controller.

What is working: My javascript is working to extract the user's timezone and timezone offset and save these two variables into the session. The following is my working JS:

<script type="text/javascript">
 window.onload = function () {
     var UserTime = new Date();
     var stringtz = UserTime.toString();
     var tzstart = stringtz.indexOf("(") + 1;
     var tzend = stringtz.indexOf(")");
     var userTZ = stringtz.slice(tzstart, tzend);
     sessionStorage.setItem("userTZOffset", UserTime.getTimezoneOffset().toString());
     sessionStorage.setItem("userTZ", userTZ);
 };
</script>

What is not working: When the user signs in, I want to grab the two variables (userTZ and userTZOffset) saved in the session and create claims for them. However, when I try to pull these into my controller I get null as the values. Upon further inspection, I can see the session timeout, id, etc but the keys and values are blank.

Here is a snipped of code from my sign in action in my controller:

        var claims = UserManager.GetClaims(user.Id);

        var timezoneclaim = claims.First(c => c.Type == "UserTZ");
        UserManager.RemoveClaim(user.Id, timezoneclaim);

        var timezoneoffsetclaim = claims.First(c => c.Type == "UserTZOffset");
        UserManager.RemoveClaim(user.Id, timezoneoffsetclaim);

        var test = HttpContext.Session["userTZ"];
        var test2 = HttpContext.Session["userTZOffset"];

        UserManager.AddClaim(user.Id, new Claim("UserTZ", test.ToString()));
        UserManager.AddClaim(user.Id, new Claim("UserTZOffset", test2.ToString()));

I set breakpoints on this and walk through the code but everytime, test and test2 are null. When I look into the session itself on the breakpoints I see SessionId, Timeout, etc but the count is 0 and the Key count is 0.

I've tried:

  1. Adding remove name="Session" and add name="Session" type="System.Web.SessionState.SessionStateModule" to my webconfig based on a similar issue I found here.
  2. I tried adding the Microsoft.Aspnet.Session nuget package and following this tutorial but my project's startup.cs doesn't have a ConfigureServices section and adding my own didn't work either.
  3. I set the session state to InProc in the webconfig based on what I found here but again, nothing changed.

Thoughts?

  • have you tried initializing the Session variable inside of the Global.asax file inside the Application_Start event or in normal asp.net the same file would have a Session_Start event.. check out this link for some pointers / hints https://stackoverflow.com/questions/560084/session-variables-in-asp-net-mvc – MethodMan Nov 29 '17 at 19:00
  • You can't. The HttpContext.Session is serverside and has no knowledge of - or access to - the clientside (DOM) localStorage or sessionStorage. These are only for the browser. You have to explicitely send the data from Javascript to the server, for example through an AJAX call, Form POST or some other mechanism. – Juliën Nov 29 '17 at 19:08
  • have you also tried the following in your case - `HttpContext.Current.Session["userTZ"]` – MethodMan Nov 29 '17 at 19:08
  • @MethodMan `HttpContext.Current.Session["userTZ"]` gives me a build error because HttpContext doesn't have "Current" in my solution for some reason. Is there a special using statement I have to add? VS tells me to use CurrentHandler or CurrentNotification instead. Would either of these make sense to use? – Nicholas Chivers Nov 29 '17 at 19:18
  • yes there is a using statement but read the link I posted it's different in MVC than normal asp.net web applications – MethodMan Nov 29 '17 at 19:19

2 Answers2

1

You cannot use HttpContext.Session["userTZ"], because data passed from client-side are not stored inside server-side Session State. Instead, you will need to use HiddenValue to pass those values back to server.

enter image description here

LoginViewModel

public class LoginViewModel
{
    ...        
    public string UserTZ { get; set; }        
    public string UserTZOffset { get; set; }
}

View

@using (Html.BeginForm(...))
{
     ...

    @Html.HiddenFor(m => m.UserTZ)
    @Html.HiddenFor(m => m.UserTZOffset)
}

<script type="text/javascript">
    $(function() {
        var UserTime = new Date();
        var stringtz = UserTime.toString();
        var tzstart = stringtz.indexOf("(") + 1;
        var tzend = stringtz.indexOf(")");
        var userTZ = stringtz.slice(tzstart, tzend);
        $("#@Html.IdFor(m => m.UserTZOffset)").val(UserTime.getTimezoneOffset().toString());
        $("#@Html.IdFor(m => m.UserTZ)").val(userTZ);
    });
</script>

Controller

[HttpPost]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    string userTZ = model.UserTZ,
           userTZOffset = model.UserTZOffset;
    ...
}
Win
  • 61,100
  • 13
  • 102
  • 181
0

Sessions are maintained at the server side. So if you want to store the user timezone and offset you should pass them from client to the mvc controller based on some event from the client like login button click. Then on the server you could store them in the session variable and for the subsequent requests in the same session you can retrieve these values on the server. For the subsequent requests you can pass these session values from your controller to other views also (using ViewBag / Viewdata). Please let me know if you need a code snippet for this.

Nishant Shrivastava
  • 389
  • 1
  • 3
  • 17