Sunday, November 6, 2011

Building a dynamic quiz application in ASP.net MVC

The quiz application I have build works just like that of W3Schools I got the inspiration from here and I wanted to understand more on asp.net MVC scafolding and Entity framework Code first. I set on my journey to write the application. Here is how it should work.
  • The user goes to the quiz page to take the quiz
  • The quiz has a question and a list of answers choices to choose from.
  • When the user clicks on the next button , a new question is loaded dynamically.
  • When the questions are completed the user is sent to a page showing his or her results.

Some ASP.Net MVC stuff

I used code first method by making poco classes and scaffolded all my controllers and i got all my CRUD methods an views for the controllers I choosed. Asp.net MVC Entity framework now the default database object relational mapper for the framework.To know more about Code first and the new scaffolding in Asp.net MVC check out this link.Scaffolding and Entity framework code first The next thing for me was to decide of what real life objects can be used and how they are connected.In this case
  • I will need a to represent the question, the answer, and the answer choices.
  • I needed one object to bring all these other object together and that is the Quiz object .
  • I needed another object to manage the quiz since I decided to store the users answers in the memory.
Here are the classes and the ASP.net MVC will build the database using EF code first based on certain conventions you have to follow for it to be right .(Check out the tutorial link above)
To manage the quiz I use the Singleton pattern .The is only one quiz in the memory when you start until you finish. The quiz manager manages all events related to the quiz in the memory .I did not want to use the session object because wanted an optimal and a modular solution for the manager. Here is the code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MyQuiz.Abstract;

namespace MyQuiz.Models
{
    public class QuizManager
    {
        static QuizManager instance;
        private QuizContext db = new QuizContext();
        int questionId = 1;
        public bool IsComplete = false;
        public Quiz quiz;

        private QuizManager()
        {            
            quiz = new Quiz();
            quiz.StartTime = DateTime.Now;
            quiz.QuizId = 1;
            quiz.Score = 0 ;
        }

        public static QuizManager Instance
        {
            get
            {
                if (instance == null)
                    instance = new QuizManager();
                return instance;
            }
        }

        public Question LoadQuiz()
        {
            var question = db.Questions.Find(questionId);
            return question;
        }

        public void SaveAnswer(string answers)
        {
            var question = db.Questions.Include("Answers").Where(x => x.QuestionId == questionId).Single();
            if (question.Answers.AnswerText == answers)
             quiz.Score++;
        }

        public bool MoveToNextQuestion()
        {
            bool canMove = false;

            if ( db.Questions.Count() > questionId)
            {
                questionId++;
                canMove = true;
            }

            return canMove;
        }

        public bool PreviosQuestion()
        {
            bool canMove = false;

            if (questionId > 1)
            {
                questionId--;
                canMove = true;
            }

            return canMove;
        }     
    }
}

The home controller that sends the quiz to the view was implemented this way
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MyQuiz.Models;

namespace MyQuiz.Controllers
{
    public class HomeController : Controller
    {   

        public ActionResult Index()
        {   
            var question = QuizManager.Instance.LoadQuiz();
            return View(question);
        }
        [HttpPost]
        public ActionResult Index(string answer, int questionId)
        {   
            if(QuizManager.Instance.IsComplete) // Prevent score increase when quix has been completed
             return RedirectToAction("ShowResults");     
          
            QuizManager.Instance.SaveAnswer(answer);
            if (QuizManager.Instance.MoveToNextQuestion())
            {
                var question = QuizManager.Instance.LoadQuiz();
                return View(question);
            }
            QuizManager.Instance.IsComplete = true;
            return RedirectToAction("ShowResults");  
        }
        public ActionResult About()
        {
            return View();
        }
        public ActionResult ShowResults()
        {
            return View(QuizManager.Instance.quiz);
        }
    }
}

The View of the quiz . I use the JQuery live(---) function that allows for asynchronous loading and event handling on the page . After getting the response from the controller I simply replace the quiz div area with new questions using the replaceWith(---) function in JQuery. The process continuous until the user answers the last question .
@model MyQuiz.Models.Question
@{
    ViewBag.Title = "Index";
}

@using (Html.BeginForm("Index", "Home")) {

@Model.QuestionText

@Html.HiddenFor(x => x.QuestionId)

  • @foreach (var choice in Model.AnswerChoices) {
      @Html.RadioButton("answer", @choice.Choices) @choice.Choices
    }
  • }

    The result page just displays the results of the quiz .Here is the source
    @model MyQuiz.Models.Quiz
    
    @{
        ViewBag.Title = "ShowResults";
    }
    
    

    ShowResults

    Your total score is @Model.Score

    Here is a screen shot of the final application

    • There is more to add like scaffolding repositories.
    • Use Dependency injection to reduce coupling of objects

    Here is the source code if want to play with it. I moved the source code to Github since some readers could not access the source code on google drive. I took advantage to play with the new Github for windows which I find intresting since i have always used Apache Subversion, svn.
    I have made some improvement on the code like moving it to MVC4  and  you can see the final application running here  MVC Quiz Application on  AppHarbor (I love these guys)
    Happy programming !

    46 comments:

    1. Thank you for this. Any chance you could post the source somewhere other than Google Docs? It's blocked at my work so I can't see the source. Thanks!

      ReplyDelete
    2. I will do that.I have been thinking about github or codeplex.I will try to push the code to one of these online repositories

      ReplyDelete
    3. Thank You for sharing. At my work, I am not allowed to install any thing. I am starting to work on a standalone quiz module and your project looks great. If publishing on codeplex is a lot of work, can you e-mail me a zip file.
      Thanks!
      Chandrika
      ChandrikaHarathi@yahoo.com

      ReplyDelete
    4. Thanks for sharing this..Please do let us know where can we find this code.
      Thanks,
      Vinod

      ReplyDelete
    5. https://github.com/ngalakvist/Quiz/tree/master/MyQuiz-2012-07-01/MyQuiz

      ReplyDelete
    6. This is great, nicely broken into classes and very well thought out entirely. Thanks for sharing!

      ReplyDelete
    7. Hi downloaded all files from https://github.com/ngalakvist/Quiz/tree/master/MyQuiz-2012-07-01/MyQuiz

      but what about database? how do i generate it ? i'm using EF4
      please guide thanks

      ReplyDelete
    8. I have added a file to generate the database for you when you download the application. First you need to install Sql management studio express on your machine.

      ReplyDelete
    9. Thanks a ton,
      I have generated database and tables successfully, also added Model1.edmx file and generated classes using POCO generator in Models folder.

      Now we don't need to use `QuizContext.cs` class ? as we have generated using POCO ?

      Also we need to made some changes into `QuizeManager.cs` like
      public class QuizManager:IQuizManager
      {
      public Entities1 db = new Entities1();
      // public QuizContextdb = new QuizContext();

      please correct me ?

      I'm getting many error as POCO giving us `ObjectSet` instead `DataSet` ?

      Error :

      // GET: /Quiz/Edit/5

      public ActionResult Edit(int id)
      {
      Quiz quiz = db.Quizs.Find(id);
      return View(quiz);
      }

      Does not contain definition Find()

      ReplyDelete
    10. I wrote this app a while ago. Some of the software like EF and MVC framework have new versions now. Everything cannot be the same like when i wrote it.I will advice you to use the concept and the model i used to create your own app. That's what i will do especially if you are using VS2012.

      ReplyDelete
    11. thanks I made changes successfully :), may i know why this table is there in you db 'EdmMetadata' ? please clarify the use ?

      ReplyDelete
    12. Do a search for EdmMetadata in google and click on the first link.

      ReplyDelete
    13. thanks may i know why we have columns like starttime, duration etc into table dbo.Quizs as it is haven't codded anywhere?

      ReplyDelete
    14. I wanted to have a timer for each question and a displayed count down.You can implement that if you like and improve on the application. After say 10 seconds the next question is shown.

      ReplyDelete
    15. Hi there
      Thanks for sharing this.

      I can't locate the create table scripts or the MDF files on the github repository. Can you please advice?

      ReplyDelete
    16. Oh great. Just awesome tutorial. I have also created a script which dynamically receives the data from JSON and shows it one-by-one. The score will also be calculated side by side.

      You can check this example to know more.

      ReplyDelete
    17. hello Ngala. I am unable to attach or onfigure database from this application. Can you please guide me.. if possible can you please attach a DB script so that I can continue.

      ReplyDelete
    18. I wanna pull data from db to a list, and then once time click Next, I get one question from the list. How can I do that? Please help me

      ReplyDelete
      Replies
      1. Hello. If you want to get all the questions to a list and get one question at a time from there, Ask yourself how you are going to save state if all the data is gotten and stored on a list .I do not know why you want to do this but anyway you can proceed by.
        Get all the questions from the DB
        Save them to a list or
        Create a queue and add the questions from it and pop out questions from it.
        Good luck !

        Delete
    19. Hi Ngala

      Can you please provide the sample data?

      Best Regards,
      Damo

      ReplyDelete
    20. Hi,

      I need the previous button functionality

      ReplyDelete
    21. Hi ,

      I need the previous button functionality and code

      ReplyDelete
    22. Opening this on vs2010 gives an error - doesn't support this installation. What to do!! Can u help

      ReplyDelete
    23. Can you provide details code which is writtten in view

      ReplyDelete
    24. Here is the link to the source code of this application. It on Github so can get it and make it run on ýour machine. See that you have the database well configured rightly.
      https://github.com/ngalakvist/Quiz/tree/master/MyQuiz-2012-07-01/MyQuiz/MyQuiz
      regards
      Ngala Talla

      ReplyDelete
    25. Please talk me how download source code and how run database? Thanks you!

      ReplyDelete
    26. Nice Project.
      Please send me your source code. My email is gianguyen4391dn@gmail.com.
      Thanks and Best Regards

      ReplyDelete
    27. please send me code i will be very thankful to you

      ReplyDelete
    28. please send me code i will be very thankful to you

      ReplyDelete
    29. You have created a very good application.Can you please share the db of this application..i have created but i am getting problems

      ReplyDelete
    30. Thanks for your comment .Everything is on github. The model you see reflects the database . From the model the database tables and keys are created using Entityframework. Its a model driven development application

      ReplyDelete
    31. First off, thank you so much for this example. It's very well thought out and built accordingly. I'm having a run-time error when I run it (I'm very new to MVC but have some experience with C#). The error is a null reference of an object instance from the Home/Index page where the "@Model.QuestionText" is used. I've been very careful to mimic your code, but I'd really appreciate some help figuring it out if you have time. I can send you my project files if you want? Please let me know. Thanks again! (my email should be on my google profile)

      ReplyDelete
      Replies
      1. Nevermind, I believe I have it figured out now. Thanks. I didn't think to look at my QuestionId number in my DB. It was "2" instead of "1" (QuizManager.cs).

        Delete
    32. Thanks for your comments and good to know that you figured it out .

      ReplyDelete
    33. I am using visual studio 2017 source code gives error. If i run your code its not working... how to fix please help me

      ReplyDelete
    34. Dear Ngala Sir, I am looking for a online quiz application in asp.net with sql db supporting in back-end data. So i request you to please help me in this concern.

      ReplyDelete
    35. Really impressed! Everything is very open and very clear clarification of issues. It contains truly facts. Your website is very valuable. Thanks for sharing. עלויות בנייה פרטית

      ReplyDelete
    36. I admire this article for the well-researched content and excellent wording. I got so involved in this material that I couldn’t stop reading. I am impressed with your work and skill. Thank you so much. www.dynamicmarketing.sg/seo-consultant-singapore

      ReplyDelete
    37. Applying for an Operators licence To apply for a new operator licence you will need to complete a form called "GV79" fokuszpalyazat.hu form. You can read the associated GV79 (G) guidance notes to help you with the application.

      ReplyDelete
    38. It sounds promising. I fixed all compilation errors but as "MyQuiz database" in github only generated the database, not the tables, it caused the unhandled exception at line #37 ("var question = db.Questions.Find(questionId);" in QuizManager.cs.

      ReplyDelete
    39. Your business can reap myriad benefits by getting an Android application developed. You can take the advantage of Android's huge market. There are many highly skilled developers available to build tailored and cost-effective apps. The built-in functionality of Android devices also supports developers in creating feature-rich applications. Android apps will thus help your business to sustain the competition by quickening its time-to-market and enhancing the ROI. Mythical Hack for sweatcoin

      ReplyDelete

    Machine learning is the future

    I am very enthusiastic about machine learning and the potential it has solve tough problems. Considering the fact that the amount of data we...