0

In my AP.NET MVC application I'm setting a session variable from JQuery like below.

HTML

 <a href="/Time" onclick="SetTraineeModel({{userId}})"><img src='../Content/themes/base/img/icon-arrow-table-view.png'></a>

abc.js

function SetTraineeModel(userId) {
    $.ajax({
        url: $('#rootUrl').val() + "Notifications/SetTraineeModel",
        async: false,
        data: {
            Id: userId
        },
        success: function (data) {
        }
    })
}

The session variable is successfully set in the method SetTraineeModel of Notifications Controller.

However the variable is null when the href method is hit after the click handler. i.e in the method Index of Time controller.

I'm not sure why the session variable is lost in this scenario?

Note: {{userId}} above is from handlebars.js template.

Here is my Controller method:

 public void SetTraineeModel(string Id)
        {
            var model = new TraineeModel();
            model.CurrentTraineeId = Id;
            HttpContext.Current.Session["CurrentTrainee"] = model;
        }
PNDev
  • 590
  • 1
  • 8
  • 23
  • Plz upload your controller too – habib Sep 27 '18 at 05:09
  • @habib I have edited the question to include controller method. – PNDev Sep 27 '18 at 05:13
  • "However the variable is null when the href method is hit after the click handler. i.e in the method Index of Time controller." please provide more info. – habib Sep 27 '18 at 05:22
  • @habib After the click handler SetTraineeModel is executed, as I'm not preventing the default, The page is routed to '/Time' url. With this URL the route is configured to hit Index method of Time controller. After the control hits the Index method the session variable HttpContext.Current.Session["CurrentTrainee"] is null. – PNDev Sep 27 '18 at 05:25
  • Well, I think when `onclick` event triggered for provided anchor, it doesn't send AJAX callback, instead it just heading to `Time` action in `href` method. Try `preventDefault()` before using `$.ajax()`. – Tetsuya Yamamoto Sep 27 '18 at 05:25
  • @Tetsuva the AJAX callback is successfully sent and i could debug the SetTraineeModel controller method well before href action is called. – PNDev Sep 27 '18 at 05:29
  • @PNDev there is noting wrong in this code. Is there else you are accessing session? – habib Sep 27 '18 at 05:31
  • @habib no. You are right I don't see anything wrong in the code, but it doesn't work :| – PNDev Sep 27 '18 at 05:34
  • Since the `Session` state tied to worker process(es) and depends to session state mode, check if you're using multiple worker processes, performing recycles or creating duplicate session cookies for anchor link request. – Tetsuya Yamamoto Sep 27 '18 at 05:35
  • I even tried to submit a form where I'm setting the session variable in the post action. But the result was same. – PNDev Sep 27 '18 at 05:36

3 Answers3

0
 <a href="/Time" onclick="SetTraineeModel({{userId}})"><img src='../Content/themes/base/img/icon-arrow-table-view.png'></a>

As you are calling /Time/Index and SetTraineeModel both simultaneously. It seems that you /Time/Index page loaded before setting your Session.

Please try this.

<a href="#" onclick="SetTraineeModel({{userId}})"><img src='../Content/themes/base/img/icon-arrow-table-view.png'></a>

And redirect to Time/Index inside your SetTranineeModel after setting your Session.

public ActionResult SetTraineeModel(string Id)
{
    var model = new TraineeModel();
    model.CurrentTraineeId = Id;
    HttpContext.Current.Session["CurrentTrainee"] = model;
    return RedirectToAction("Index", "Time", null);
}

Alternative solution

<a href="#" onclick="SetTraineeModel({{userId}})"><img src='../Content/themes/base/img/icon-arrow-table-view.png'></a>

Then instead of changing your Action you can redirect to /Time/Index using JavaScript.

function SetTraineeModel(userId) {
$.ajax({
    url: $('#rootUrl').val() + "Notifications/SetTraineeModel",
    async: false,
    data: {
        Id: userId
    },
    success: function (data) {
        location.href='@Url.Action("Index","Time",null)';
    }
});
}

Hopefully, it will solve your problem.

habib
  • 2,366
  • 5
  • 25
  • 41
  • Thanks for the answer. The ajax call was made correctly before the href method. I have tried to explain the issue in my answer. – PNDev Sep 27 '18 at 06:35
0

This setup will first call /Time/Index action inside href before executing AJAX, hence the session state with corresponding key still has null value:

<a href="/Time" onclick="SetTraineeModel({{userId}})"><img src='../Content/themes/base/img/icon-arrow-table-view.png'></a> 

Since the session state value set from AJAX call, it is necessary to prevent triggering of default action of anchor link with preventDefault() and redirect to Index action method of Time after successful AJAX callback:

Anchor markup

<a href="#" id="time"><img src='../Content/themes/base/img/icon-arrow-table-view.png'></a>

jQuery

$('#time').click(function (e) {
    e.preventDefault();

    // assign userId with unencoded value
    var userId = {{{userId}}};

    $.ajax({
        url: $('#rootUrl').val() + "Notifications/SetTraineeModel",
        async: false,
        data: {
            Id: userId
        },
        success: function (data) {
            location.href = "@Url.Action("Index", "Time")";
        }
    });
});

If you want to use vanilla JS, put this line inside SetTraineeModel() function (don't forget to set id attribute for anchor link first):

document.getElementById('time').addEventListener('click', function(e) {
    e.preventDefault();
}
Tetsuya Yamamoto
  • 24,297
  • 8
  • 39
  • 61
  • Thanks for the answer. The ajax call was made correctly before the href method. I have tried to explain the issue in my answer. – PNDev Sep 27 '18 at 06:36
0

The issue here is because of SessionStateBehaviour. The controller had the attribute

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]

to process the concurrent requests and reduce the time take for multiple ajax calls.

Even though the controller had SessionStateBehaviour set to readonly, it allowed to updated the session in the controller action. From the docs here this behavior is by design itself.

I fixed this issue by moving the controller Action to a different controller.

I know this issue has been discussed multiple times. But I din't find any post relating the issue what I had directly to the SessionStateBehaviour. So Leaving this thread here with a hope that it will help someone.

Please refer to this post for more details.

PNDev
  • 590
  • 1
  • 8
  • 23