Example #1
0
        /// <summary>
        /// Skip the question. Returns the next 2 questions like Answer but they aren't shown
        /// asynchronously - make the user wait for skipping questions. Doesn't update the 
        /// answer cache.
        /// </summary>
        public async Task<JsonResult> Skip(AnswerViewModel input)
        {
            var profileId = GetMyProfileId();

            var answer = new Answer
            {
                ProfileId = profileId,
                QuestionId = (short)input.QuestionId,
                ChoiceIndex = null,
                ChoiceAccept = 0,
                ChoiceWeight = 0,
            };

            await _quesRepo.AnswerAsync(answer);

            var nextQuestions = _quesRepo.Next2Questions(profileId);

            return Json(nextQuestions);
        }
Example #2
0
        /// <summary>
        /// Add/Updates a user's answer in the database, and then calls MatchApiClient to
        /// update the cache. Responsible for keeping DB and cache in sync so wraps these
        /// operations in a transaction. 
        /// 
        ///   - If getNextFlag = true get the next 2 questions and return them as JSON
        ///   - Otherwise return the user's validated answer
        ///   - Sets forceRecalculateMatches = true if user answered less than 10 questions (so new users can see results immediately)
        /// 
        /// More info about TransactionScope (limitations):
        /// https://msdn.microsoft.com/en-us/data/dn456843.aspx
        /// 
        /// </summary>
        public async Task<JsonResult> Answer(AnswerViewModel input, bool getNextFlag = true)
        {
            var profileId = GetMyProfileId();

            _matchApiClient = GetMatchApiClient();

            var answer = new Answer
            {
                ProfileId = profileId,
                QuestionId = (short)input.QuestionId
            };

            //Convert checkboxes to bit array for Acceptable choices
            byte acceptBits = 0;

            foreach (var index in input.ChoiceAccept)
            {
                acceptBits |= (byte)(1 << (index - 1));
            }

            answer.ChoiceIndex = (byte)input.ChoiceIndex;
            answer.ChoiceAccept = acceptBits;
            answer.ChoiceWeight = (byte)input.ChoiceImportance;

            //We should do some user input validation
            if(!_quesRepo.ValidateAnswer(answer))
            {
                //invalid answer - return not OK
                Response.StatusCode = (int)HttpStatusCode.BadRequest;
                return Json(null);
            }
            
            // Isolation Level: Read Committed
            // Timeout        : 5 minutes
            var options = new TransactionOptions
            {
                IsolationLevel = IsolationLevel.ReadCommitted,
                Timeout = TimeSpan.FromMinutes(5)
            };

            int count;

            //Update DB and Cache in a transaction
            //By default if scope.Complete() isn't called the transaction is rolled back.
            using (var scope = new TransactionScope(TransactionScopeOption.Required, options, TransactionScopeAsyncFlowOption.Enabled))
            {
                var t1 = _quesRepo.AnswerAsync(answer);
                var t2 = _matchApiClient.AnswerAsync(answer);

                //await Task.WhenAll(t1, t2);
                await t1;
                count = await t2;

                scope.Complete();
            }

            //Update the Activity feed
            if(IsOkToAddActivity(OkbConstants.ActivityCategories.AnsweredQuestion))
            {
                //Get the question text
                var ques = _quesRepo.GetQuestion(input.QuestionId);
                var choiceText = "";                
                choiceText = ques.Choices[((int)answer.ChoiceIndex - 1) % ques.Choices.Count];               
                _feedRepo.AnsweredQuestionActivity(profileId, ques.Text, choiceText);
                UpdateActivityLastAdded(OkbConstants.ActivityCategories.AnsweredQuestion);
            }

            //set forceRecalculateMatches = true if answered less than 10 questions
            if (count < 10)
            {
                Session[OkbConstants.FORCE_RECALCULATE_MATCHES] = true;
            }

            IList<QuestionModel> nextQuestions = null;

            //Get the next questions
            if (getNextFlag)
            {
                nextQuestions = _quesRepo.Next2Questions(profileId);
                return Json(nextQuestions);
            }
            else
            {
                return Json(answer);
            }            
        }