locked
Problem with Session when getting string data to the action of controller RRS feed

  • Question

  • User1255309776 posted

    Hi guys,

    As some of you knows, I'm developing a quiz application. I have timer in question view and this time I need to get the time between opening the question view and submitting the answer. Then I substruct that interval from 60 in order to get remained seconds which will be the point of the question if the answer is right.  Here is the details:

    View

    @model Intellect.Models.ViewModels.AdminViewModel
    
        <div class="questioncontainer">        
            <form asp-action="Question" asp-controller="Home" asp-route-id="@Model.NextQuestion.Id" asp-route-count="@ViewBag.Equestions">
                <div class="row">
                    <div class="col-lg-3"></div>
                    <div class="col-lg-6 col-sm-12">
                        <table>
                            <tr>
                                <th>Qaliq vaxt</th>
                            </tr>
                            <tr>
                                <td>
                                    <div id="time"></div> 
                                </td>
                            </tr>
                        </table>
                        <div class="question">@Model.CurrentQuestion.Description </div>
                    </div>
                    <div class="col-lg-3"></div>
                </div>
                <div class="row">
                    <div class="col-lg-3 col-sm-0"></div>
                    @{
                        int n = 0;
                    }
                    @foreach (Answer item in Model.Answers)
                    {
                        if (n == 0 || n == 2)
                        {
                            @: <div class="col-lg-3 col-sm-12">
                                @: <div class="firstpart">
                                }
                                <input asp-for="@item.Id" name="@item.Id" hidden />
                                <input type="radio" asp-for="@item.Id" name="myanswer" value="@item.Id" />@item.Description
    
                                <br>
                                if (n == 1 || n == 3)
                                {
                                @:</div>
                            @:</div>
                        }
    
                        n++;
                    }
                    <div class="col-lg-3"></div>
                </div>
                <div class="row">
                    <div class="col-lg-6 col-sm-4">
    
                    </div>
                    <div class="col-lg-3 col-sm-4">
    
                    </div>
                    <div class="col-lg-3 col-sm-4">
                        <div class="nextbtn">
                            @if (ViewBag.Equestions == 0)
                            {
                                <input type="submit" value="Finish" />
                            }
                            else
                            {
                                <input type="submit" value="Next" />
                            }
    
                        </div>
                    </div>
                </div>
            </form>
    
        </div>
    
    @section Script{ 
        <script>
            function StartTimer(seconds) {
                var intSeconds = seconds;
                var timer = setInterval(myTimer, 1000);
                function myTimer() {
                    if (intSeconds < 0) {
                        Alert("bitdi")
                        clearInterval(timer)
                        return;
                    }
                    document.getElementById("time").innerText = intSeconds;
                    intSeconds--;
                }
            }
            StartTimer(60);
    
        </script>
    }

    Controller

     public class HomeController : Controller
        {
            private readonly IntellectDbContext _intellectDbContext;
            private readonly UserManager<ExamUser> _userManager;
            private readonly SignInManager<ExamUser> _signInManager;
            static int exam_id = 0;
            static int? PreviousId = 0;
            static int result = 0;
            static int correctAnswer = 0;
            static List<Question> RemainedQuestions = new List<Question>();
            static List<int> trueAnswers = new List<int>();
    
            public HomeController(IntellectDbContext intellectDbContext, UserManager<ExamUser> userManager, SignInManager<ExamUser> signInManager)
            {
                _intellectDbContext = intellectDbContext;
                _userManager = userManager;
                _signInManager = signInManager;
            }
             
            [HttpGet]
            public async Task<IActionResult> Test(int Id)
            {
                exam_id = Id;
                AdminViewModel admodel = new AdminViewModel();
                admodel.Equestions = await _intellectDbContext.Questions.Include(q => q.Answers).Where(q => q.ExamId == Id).ToListAsync();
                admodel.CurrentQuestion = await _intellectDbContext.Questions.Where(q => q.ExamId == Id).FirstOrDefaultAsync();
                RemainedQuestions = admodel.Equestions;
                PreviousId = admodel.CurrentQuestion.Id;
                return View(admodel);
            }
    
    
            [HttpGet]
            public async Task<IActionResult> Question(int Id, int count)
            {
                AdminViewModel admodel = new AdminViewModel();
                admodel.CurrentQuestion = await _intellectDbContext.Questions.Where(x => x.Id == Id).SingleOrDefaultAsync();
                admodel.Answers = await _intellectDbContext.Answers.Where(y => y.QuestionId == Id).ToListAsync();
                admodel.Equestions = await _intellectDbContext.Questions.Where(q => q.ExamId == exam_id).ToListAsync();
    
                // admodel.CurrentQuestion.Remainedtime = new TimeSpan(0, 0, 60);
                HttpContext.Session.SetString("currentQuestion_" + admodel.CurrentQuestion.Id, DateTime.Now.ToString());
    
    
                if (count > 1)
                {
                    var question = RemainedQuestions.Single(r => r.Id == admodel.CurrentQuestion.Id);
                    PreviousId = question.Id;
                    RemainedQuestions.Remove(question);
                    admodel.NextQuestion = RemainedQuestions[0];
                    count -= 1;
                }
                else
                {
                    admodel.NextQuestion = RemainedQuestions[0];
                    count -= 1;
                }
    
                if (count == -1)
                {
                    return RedirectToAction(nameof(Finish));
                }
    
                ViewBag.Equestions = count;
    
                return View(admodel);
            }
    
            [HttpPost]
            public async Task<IActionResult> Question(int Id, int count, int myanswer)
            {
                AdminViewModel admodel = new AdminViewModel();
                admodel.CurrentQuestion = await _intellectDbContext.Questions.Where(x => x.Id == Id).SingleOrDefaultAsync();
                admodel.Answers = await _intellectDbContext.Answers.Where(y => y.QuestionId == Id).ToListAsync();
                admodel.Equestions = await _intellectDbContext.Questions.Where(q => q.ExamId == exam_id).ToListAsync();
    
                //  admodel.CurrentQuestion.Remainedtime = new TimeSpan(0, 0, 60);
               // HttpContext.Session.SetString("currentQuestion_" + admodel.CurrentQuestion.Id, DateTime.Now.ToString());
                var interval = DateTime.Now - DateTime.Parse(HttpContext.Session.GetString("currentQuestion_" + Id));
    
                correctAnswer = _intellectDbContext.Answers.Where(a => a.QuestionId == PreviousId && a.Correct == true).SingleOrDefault().Id;
    
                if (_signInManager.IsSignedIn(User))
                {
                    ExamUser examTaker = await _userManager.GetUserAsync(HttpContext.User);
    
                    examTaker.TestTaker = await _intellectDbContext.TestTakers
                                                   .Include(tt => tt.UserQuestions) 
                                                   .Where(t => t.Id == examTaker.TestTakerId) 
                                                   .FirstOrDefaultAsync();
                    admodel.CurrentQuestion = examTaker.TestTaker.UserQuestions.Select(u => u.Question).Where(x => x.Id == Id).SingleOrDefault();
                    if (myanswer == correctAnswer)
                    {
                        admodel.CurrentQuestion.Score = 60 - (int)interval.TotalMilliseconds / 1000;
                        await _intellectDbContext.SaveChangesAsync();
                        // admodel.CurrentQuestion.Score = result;
                    }
                }
                 
                    if (count > 1)
                {
                    var question = RemainedQuestions.Single(r => r.Id == admodel.CurrentQuestion.Id);
                    PreviousId = question.Id;
                    RemainedQuestions.Remove(question);
                    admodel.NextQuestion = RemainedQuestions[0];
                    count -= 1;
                }
                else
                {
                    admodel.NextQuestion = RemainedQuestions[0];
                    count -= 1;
                }
    
                if(count == -1)
                {
                    return RedirectToAction(nameof(Finish));
                }
    
                ViewBag.Equestions = count;
    
                return RedirectToAction(nameof(Question));
            }
         }

    When I run the application, the following errors comes (refer to link) when clicking on Next to get to the next question view:  https://prnt.sc/s6y9vy

    As you see, action (Question) in controller cannot get string data from session to parse it. 

    The problem lies here:        var interval = DateTime.Now - DateTime.Parse(HttpContext.Session.GetString("currentQuestion_" + Id));

    Please, assist in solving this issue. 

    Monday, April 27, 2020 6:57 PM

All replies

  • User711641945 posted

    Hi FaridGN,

    What is your Test action used to do?

    From your code,it seems you render the view by HttpGet Question action.If you request the url like:Home/Question?id=1&count=34,you could set the session with name `currentQuestion_1`.

    Please set breakpoint to the following line:

    HttpContext.Session.SetString("currentQuestion_" + admodel.CurrentQuestion.Id, DateTime.Now.ToString());
    

    To check if it contains the session with the correct key name:

    Best Regards,

    Rena

    Tuesday, April 28, 2020 9:40 AM
  • User1255309776 posted

    Dear Rena,

    Sorry for late reply. The test action returns view before starting the test where test taker will see exam rules (not written yet on that page so far), and click start to start the quiz.

    Does Session name make sense when it comes to getting data in quiz session and then calculating its duration until next button is clicked for the next question?

    How would you implement Question action to make session work like I wanted if you were me to do this? Can you show with code? 

    Thanks in advance

    Monday, May 4, 2020 5:53 PM