QUIZ Application With ASP.NET MVC 5

Introduction

There are so many people who asked in the forums how we can build a quiz application using ASP.NET MVC. I would like to share with you a simple solution to achieve this application.

In this post, we will build our quiz application with an easy and simple approach. But you should have some basic skills in ASP.NET MVC 5, jQuery, and Bootstrap. I hope it will be helpful for you.

Prerequisites

Make sure you have installed Visual Studio 2015 (.NET Framework 4.5.2) and SQL Server.

In this post, we are going to,

  • Create Database.
  • Create an MVC application.
  • Configuring Entity framework ORM to connect to the database.
  • Create our Quiz controller.
  • Create Razor pages in order to build our application.

SQL Database part

Here, you will find the script to create a database and tables.

Create Database

USE [master]  
GO  

/****** Object:  Database [DBQuiz]    Script Date: 11/18/2017 10:57:17 AM ******/  
CREATE DATABASE [DBQuiz]  
  CONTAINMENT = NONE  
  ON  PRIMARY   
  ( 
    NAME = N'DBQuiz', 
    FILENAME = N'c:\Program Files (x86)\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\DBQuiz.mdf', 
    SIZE = 3072KB, 
    MAXSIZE = UNLIMITED, 
    FILEGROWTH = 1024KB 
  )  
  LOG ON    
  ( 
    NAME = N'DBQuiz_log', 
    FILENAME = N'c:\Program Files (x86)\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\DBQuiz_log.ldf', 
    SIZE = 1024KB, 
    MAXSIZE = 2048GB, 
    FILEGROWTH = 10% 
  )  
GO  

ALTER DATABASE [DBQuiz] SET COMPATIBILITY_LEVEL = 110  
GO  

IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))  
BEGIN  
    EXEC [DBQuiz].[dbo].[sp_fulltext_database] @action = 'enable'  
END  
GO  

ALTER DATABASE [DBQuiz] SET ANSI_NULL_DEFAULT OFF    
GO  

ALTER DATABASE [DBQuiz] SET ANSI_NULLS OFF    
GO  

ALTER DATABASE [DBQuiz] SET ANSI_PADDING OFF    
GO  

ALTER DATABASE [DBQuiz] SET ANSI_WARNINGS OFF    
GO  

ALTER DATABASE [DBQuiz] SET ARITHABORT OFF    
GO  

ALTER DATABASE [DBQuiz] SET AUTO_CLOSE OFF    
GO  

ALTER DATABASE [DBQuiz] SET AUTO_CREATE_STATISTICS ON    
GO  

ALTER DATABASE [DBQuiz] SET AUTO_SHRINK OFF    
GO  

ALTER DATABASE [DBQuiz] SET AUTO_UPDATE_STATISTICS ON    
GO  

ALTER DATABASE [DBQuiz] SET CURSOR_CLOSE_ON_COMMIT OFF    
GO  

ALTER DATABASE [DBQuiz] SET CURSOR_DEFAULT GLOBAL    
GO  

ALTER DATABASE [DBQuiz] SET CONCAT_NULL_YIELDS_NULL OFF    
GO  

ALTER DATABASE [DBQuiz] SET NUMERIC_ROUNDABORT OFF    
GO  

ALTER DATABASE [DBQuiz] SET QUOTED_IDENTIFIER OFF    
GO  

ALTER DATABASE [DBQuiz] SET RECURSIVE_TRIGGERS OFF    
GO  

ALTER DATABASE [DBQuiz] SET DISABLE_BROKER    
GO  

ALTER DATABASE [DBQuiz] SET AUTO_UPDATE_STATISTICS_ASYNC OFF    
GO  

ALTER DATABASE [DBQuiz] SET DATE_CORRELATION_OPTIMIZATION OFF    
GO  

ALTER DATABASE [DBQuiz] SET TRUSTWORTHY OFF    
GO  

ALTER DATABASE [DBQuiz] SET ALLOW_SNAPSHOT_ISOLATION OFF    
GO  

ALTER DATABASE [DBQuiz] SET PARAMETERIZATION SIMPLE    
GO  

ALTER DATABASE [DBQuiz] SET READ_COMMITTED_SNAPSHOT OFF    
GO  

ALTER DATABASE [DBQuiz] SET HONOR_BROKER_PRIORITY OFF    
GO  

ALTER DATABASE [DBQuiz] SET RECOVERY SIMPLE    
GO  

ALTER DATABASE [DBQuiz] SET MULTI_USER    
GO  

ALTER DATABASE [DBQuiz] SET PAGE_VERIFY CHECKSUM    
GO  

ALTER DATABASE [DBQuiz] SET DB_CHAINING OFF    
GO  

ALTER DATABASE [DBQuiz] SET FILESTREAM(NON_TRANSACTED_ACCESS = OFF)    
GO  

ALTER DATABASE [DBQuiz] SET TARGET_RECOVERY_TIME = 0 SECONDS    
GO  

ALTER DATABASE [DBQuiz] SET READ_WRITE    
GO  

Create Tables

After creating the database, we will move to create all the needed tables.

Users Table

USE [DBQuiz]  
GO  

/****** Object:  Table [dbo].[Users]    Script Date: 11/18/2017 10:58:08 AM ******/  
SET ANSI_NULLS ON  
GO  

SET QUOTED_IDENTIFIER ON  
GO  

SET ANSI_PADDING ON  
GO  

CREATE TABLE [dbo].[Users] (  
    [UserID] int IDENTITY(1,1) NOT NULL,  
    [FullName] varchar(50) NULL,  
    [ProfilImage] varchar(50) NULL,  
    CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED  
    (  
        [UserID] ASC  
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]  
) ON [PRIMARY]  

GO  

SET ANSI_PADDING OFF  
GO  

Quiz Table

USE [DBQuiz]  
GO  

/****** Object:  Table [dbo].[Quiz]    Script Date: 11/18/2017 10:58:43 AM ******/  
SET ANSI_NULLS ON  
GO  

SET QUOTED_IDENTIFIER ON  
GO  

SET ANSI_PADDING ON  
GO  

CREATE TABLE [dbo].[Quiz] (  
    [QuizID] int IDENTITY(1,1) NOT NULL,  
    [QuizName] varchar(80) NULL,  
    CONSTRAINT [PK_Quiz] PRIMARY KEY CLUSTERED  
    (  
        [QuizID] ASC  
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]  
) ON [PRIMARY]  

GO  

SET ANSI_PADDING OFF  
GO  

Questions Table

USE [DBQuiz]  
GO  

/****** Object:  Table [dbo].[Questions]    Script Date: 11/18/2017 10:59:29 AM ******/  
SET ANSI_NULLS ON  
GO  

SET QUOTED_IDENTIFIER ON  
GO  

SET ANSI_PADDING ON  
GO  

CREATE TABLE [dbo].[Questions] (  
    [QuestionID] int IDENTITY(1,1) NOT NULL,  
    [QuestionText] varchar(max) NULL,  
    [QuizID] int NULL,  
    CONSTRAINT [PK_Questions] PRIMARY KEY CLUSTERED  
    (  
        [QuestionID] ASC  
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]  
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]  

GO  

SET ANSI_PADDING OFF  
GO  

ALTER TABLE [dbo].[Questions] WITH CHECK ADD CONSTRAINT [FK_Questions_Quiz] FOREIGN KEY ([QuizID])  
REFERENCES [dbo].[Quiz] ([QuizID])  
GO  

ALTER TABLE [dbo].[Questions] CHECK CONSTRAINT [FK_Questions_Quiz]  
GO  

Choices Table

USE [DBQuiz]  
GO  

/****** Object:  Table [dbo].[Choices]    Script Date: 11/18/2017 11:00:03 AM ******/  
SET ANSI_NULLS ON  
GO  

SET QUOTED_IDENTIFIER ON  
GO  

SET ANSI_PADDING ON  
GO  

CREATE TABLE [dbo].[Choices] (  
    [ChoiceID] int IDENTITY(1,1) NOT NULL,  
    [ChoiceText] varchar(max) NULL,  
    [QuestionID] int NULL,  
    CONSTRAINT [PK_Choices] PRIMARY KEY CLUSTERED  
    (  
        [ChoiceID] ASC  
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]  
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]  

GO  

SET ANSI_PADDING OFF  
GO  

ALTER TABLE [dbo].[Choices] WITH CHECK ADD CONSTRAINT [FK_Choices_Questions] FOREIGN KEY ([QuestionID])  
REFERENCES [dbo].[Questions] ([QuestionID])  
GO  

ALTER TABLE [dbo].[Choices] CHECK CONSTRAINT [FK_Choices_Questions]  
GO  

Answers Table

USE [DBQuiz]  
GO  

/****** Object:  Table [dbo].[Answers]    Script Date: 11/18/2017 11:00:46 AM ******/  
SET ANSI_NULLS ON  
GO  

SET QUOTED_IDENTIFIER ON  
GO  

SET ANSI_PADDING ON  
GO  

CREATE TABLE [dbo].[Answers] (  
    [AnswerID] int IDENTITY(1,1) NOT NULL,  
    [AnswerText] varchar(max) NULL,  
    [QuestionID] int NULL,  
    CONSTRAINT [PK_Answers] PRIMARY KEY CLUSTERED  
    (  
        [AnswerID] ASC  
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]  
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]  

GO  

SET ANSI_PADDING OFF  
GO  

ALTER TABLE [dbo].[Answers] WITH CHECK ADD CONSTRAINT [FK_Answers_Questions] FOREIGN KEY ([QuestionID])  
REFERENCES [dbo].[Questions] ([QuestionID])  
GO  

ALTER TABLE [dbo].[Answers] CHECK CONSTRAINT [FK_Answers_Questions]  
GO  

Create your MVC application

Open Visual Studio and select File >> New Project.

The "New Project" window will pop up. Select ASP.NET Web Application (.NET Framework), name your project, and click OK.

New Project

Next, a new dialog will pop up for selecting the template. We are going to choose the MVC template and click OK.

MVC template

Once our project is created, let us add the ADO.NET Entity Data Model.

Adding ADO.NET Entity Data Model

Right-click on the project name, click Add >> Add New Item.

A dialog box will pop up. Inside Visual C#, select Data >> ADO.NET Entity Data Model, and enter the name for your DbContext model as Quizz, then click Add.

ADO.NET Entity Data Model

As you can see, we have 4 model contents. We are selecting the first approach (EF Designer from the database).

4 model contents

As you can see below, we need to select the server name via the drop-down list in the "connect to a database" section. You must choose your database name and finally click OK.

Connect to a database

For the next step, the dialog Entity Data Model Wizard will pop up for choosing objects that will be used in our application. We select all the tables except sys diagrams and click Finish.

Finally, we see that the EDMX model generates all the objects, as shown below.

EDMX model

QUIZ Application

Create a controller

Now, we are going to create a Controller. Right-click the Controllers folder, go to Add >> Controller>> MVC 5 Controller - Empty>> click Add. In the next dialog, name the controller as QuizzController and then click Add.

MVC 5 Controller

Add controller

QuizzController.cs

The user needs to be authenticated by providing her/his full name, then if the user already exists in the user's table, we will redirect him to select the quiz via the dropdown list, and if not, a message will be displayed 'Sorry: the user is not found'. The responsible action is the GetUser action.

[HttpGet]  
public ActionResult GetUser()  
{  
    return View();  
}  

[HttpPost]  
public ActionResult GetUser(UserVM user)  
{  
    UserVM userConnected = dbContext.Users  
        .Where(u => u.FullName == user.FullName)  
        .Select(u => new UserVM  
        {  
            UserID = u.UserID,  
            FullName = u.FullName,  
            ProfilImage = u.ProfilImage,  
        })  
        .FirstOrDefault();  

    if (userConnected != null)  
    {  
        Session["UserConnected"] = userConnected;  
        return RedirectToAction("SelectQuizz");  
    }  
    else  
    {  
        ViewBag.Msg = "Sorry : user is not found !!";  
        return View();  
    }  
}  

GetUser.cshtml

@model QuizApplicationMVC5.viewModels.UserVM  

@{  
    ViewBag.Title = "User";  
}  

<div class="panel panel-default" style="width: 37%; margin: 20% 32%;">  
    <div class="panel-heading">Let's Begin  ^_^</div>  
    <div class="panel-body">  

        @using (Html.BeginForm("GetUser", "Quizz", FormMethod.Post))  
        {  
            @Html.EditorFor(c => c.FullName, new { htmlAttributes = new { @class = "form-control", @placeholder = "FullName ...", @style = "width:100%; margin-left: 56px;" } })<br/>  
            <button type="submit" id="Enter" class="btn btn-info btn-lg" style="width:100%;">
                <span class="glyphicon glyphicon-user"></span> Enter
            </button>  
        }  

    </div>  

    @if (ViewBag.Msg != null)  
    {  
        <div class="well well-sm well-danger"> @ViewBag.Msg </div>  
    }  
</div>  

Select Quiz [HttpGet] action is responsible for getting the list of quiz names from the quiz table and displaying them on the SelectQuizz.cshtml page.

Select Quiz [HttpPost] action accepts the quiz object as a parameter that contains the selected quiz, and after that, we will redirect the authenticated user to the quiz test action, which will display all the questions related to the selected quiz.

[HttpGet]  
public ActionResult SelectQuizz()  
{  
    QuizVM quiz = new viewModels.QuizVM();  
    quiz.ListOfQuizz = dbContext.Quizs.Select(q => new SelectListItem  
    {  
        Text = q.QuizName,  
        Value = q.QuizID.ToString()  
    }).ToList();  

    return View(quiz);  
}  

[HttpPost]  
public ActionResult SelectQuizz(QuizVM quiz)  
{  
    QuizVM quizSelected = dbContext.Quizs  
        .Where(q => q.QuizID == quiz.QuizID)  
        .Select(q => new QuizVM  
        {  
            QuizID = q.QuizID,  
            QuizName = q.QuizName,  
        })  
        .FirstOrDefault();  

    if (quizSelected != null)  
    {  
        Session["SelectedQuiz"] = quizSelected;  
        return RedirectToAction("QuizTest");  
    }  

    return View();  
}  

SelectQuizz.cshtml

@model QuizApplicationMVC5.viewModels.QuizVM  

@{  
    ViewBag.Title = "SelectQuizz";  
}  

<div class="container">  

    <div class="userConnected" style="border:2px dashed #cecaca; border-radius: 10px; margin-top: 3%;">  
        @{ Html.RenderPartial("_UserInfo");}  
    </div>  

    <div class="SelQuiz">  
        <div class="panel panel-default" style="width: 37%; margin: 20% 32%;">  
            <div class="panel-heading">Select Your Quiz  ^_^</div>  
            <div class="panel-body">  
                @using (Html.BeginForm("SelectQuizz", "Quizz", FormMethod.Post))  
                {  
                    @Html.DropDownListFor(model => model.QuizID, Model.ListOfQuizz, new { @class = "form-control", @style = "margin-left:51px;" })<br/>  
                    <button type="submit" id="Enter" class="btn btn-success btn-lg" style="width:100%;">
                        <span class="glyphicon glyphicon-ok"></span> Let's GO 
                    </button>  
                }  
            </div>  
        </div>  
    </div>  
</div>  <!-- END CONTAINER -->  

As you can see, the QuizTest [HttpGet] action will display all the questions based on the selected quiz.

QuizTest [HttpPost] action accepts the answers list as a parameter. Then it will proceed to verify all the answers submitted by the user and return the result in JSON format.

[HttpGet]
public ActionResult QuizTest()
{
    QuizVM quizSelected = Session["SelectedQuiz"] as QuizVM;
    IQueryable<QuestionVM> questions = null;

    if (quizSelected != null)
    {
        questions = dbContext.Questions.Where(q => q.Quiz.QuizID == quizSelected.QuizID)
            .Select(q => new QuestionVM
            {
                QuestionID = q.QuestionID,
                QuestionText = q.QuestionText,
                Choices = q.Choices.Select(c => new ChoiceVM
                {
                    ChoiceID = c.ChoiceID,
                    ChoiceText = c.ChoiceText
                }).ToList()
            }).AsQueryable();
    }

    return View(questions);
}

[HttpPost]
public ActionResult QuizTest(List<QuizAnswersVM> resultQuiz)
{
    List<QuizAnswersVM> finalResultQuiz = new List<viewModels.QuizAnswersVM>();

    foreach (QuizAnswersVM answser in resultQuiz)
    {
        QuizAnswersVM result = dbContext.Answers.Where(a => a.QuestionID == answser.QuestionID).Select(a => new QuizAnswersVM
        {
            QuestionID = a.QuestionID.Value,
            AnswerQ = a.AnswerText,
            isCorrect = (answser.AnswerQ.ToLower().Equals(a.AnswerText.ToLower()))
        }).FirstOrDefault();

        finalResultQuiz.Add(result);
    }

    return Json(new { result = finalResultQuiz }, JsonRequestBehavior.AllowGet);
}

QuizTest.cshtml

@model IQueryable<QuizApplicationMVC5.viewModels.QuestionVM>

@{
    int count = 1, countR = 0;
}

<div class="container">

    <!-- User Info -->
    <div class="userConnected" style="border:2px dashed #cecaca; border-radius: 10px; margin-top: 3%;">
        @{ Html.RenderPartial("_UserInfo"); }
    </div>

    <div class="Quiz">
        <h4 style="margin-top: 4%;">
            <span class="label label-info">Questions :</span>
        </h4>

        @if (Model != null && Model.Any())
        {
            foreach (var question in Model)
            {
                <div class="BlockQ" style="border: 1px solid #bdbdbd; width: 75%; border-radius: 4px; margin-top: 40px; background-color: #f0ffff; padding: 8px;">
                    <div class="Question" style="padding: 2%;">
                        <span class="label label-warning">@string.Format("{0}{1}.", "Q", count)</span>
                        <span id="@string.Format("{0}{1}", "ID_Q", count)" style="display:none;">@question.QuestionID</span>
                        <p style="display: inline; padding: 2%;" id="@string.Format("{0}{1}", "Q", count)">@question.QuestionText</p>
                    </div>

                    <div class="Choices" style="margin-left: 8%;">
                        @foreach (var choice in question.Choices)
                        {
                            <label class="radio-inline">
                                <input type="radio" name="@string.Format("{0}{1}", "inlineRadioOptions", count)" id="@string.Format("{0}{1}", "inlineRadio", countR)" value="@choice.ChoiceText" style="margin-left: -16px;"> @choice.ChoiceText
                            </label><br />
                            countR++;
                        }
                    </div> <!--END Choices-->

                    <div id="@string.Format("{0}{1}{2}", "Ans", "Q", count)">
                    </div>
                </div> <!-- END BlockQ -->
                count++;
            }
            <span id="countQuections" style="display:none;">@count</span>
            <button type="button" id="SubmitQuiz" class="btn btn-default" style="margin-top: 10px;">
                <span class="glyphicon glyphicon-ok"></span> Submit Quiz
            </button>
        }
    </div> <!-- END QUIZ -->

</div> <!-- END CONTAINER -->

@section MyScritps
{
    <script type="text/javascript">
        $(document).ready(function () {
            $('#SubmitQuiz').on('click', function () {
                //count Questions
                var sel = $('#countQuections').text();
                console.log(sel);

                var resultQuiz = [], countQuestion = parseInt(sel), question = {}, j = 1;

                for (var i = 1; i < countQuestion; i++) {
                    question = {
                        QuestionID: $('#ID_Q' + i).text(),
                        QuestionText: $('#Q' + i).text(),
                        AnswerQ: $('input[name=inlineRadioOptions' + i + ']:checked').val()
                    };

                    resultQuiz.push(question);
                }

                $.ajax({
                    type: 'POST',
                    url: '@Url.Action("QuizTest", "Quizz")',
                    data: { resultQuiz },
                    success: function (response) {
                        if (response.result.length > 0) {
                            for (var i = 0; i < response.result.length; i++) {
                                if (response.result[i].isCorrect == true) {
                                    $('#AnsQ' + j).html('<div class="alert alert-success" role="alert"><span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span> Correct answer</div>');
                                } else {
                                    $('#AnsQ' + j).html('<div class="alert alert-danger" role="alert"> <span class="glyphicon glyphicon-thumbs-down" aria-hidden="true"></span> Incorrect answer - The Good Answer is <b>' + response.result[i].AnswerQ + '</b></div>');
                                }
                                j++;
                            }
                        } else {
                            alert("Something Wrong");
                        }
                    },
                    error: function (response) {
                        // Handle error
                    }
                });

                console.log(resultQuiz);
            });
        });
    </script>
}

View Model

Don’t forget to add the following view models.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace QuizApplicationMVC5.viewModels
{
    public class UserVM
    {
        public int UserID { get; set; }
        public string FullName { get; set; }
        public string ProfilImage { get; set; }
    }

    public class QuizVM
    {
        public int QuizID { get; set; }
        public string QuizName { get; set; }
        public List<SelectListItem> ListOfQuizz { get; set; }
    }

    public class QuestionVM
    {
        public int QuestionID { get; set; }
        public string QuestionText { get; set; }
        public string QuestionType { get; set; }
        public string Anwser { get; set; }
        public ICollection<ChoiceVM> Choices { get; set; }
    }

    public class ChoiceVM
    {
        public int ChoiceID { get; set; }
        public string ChoiceText { get; set; }
    }

    public class QuizAnswersVM
    {
        public int QuestionID { get; set; }
        public string QuestionText { get; set; }
        public string AnswerQ { get; set; }
        public bool isCorrect { get; set; }
    }
}

Shared/_UserInfo.cshtml

We need to display the user details, which will be shared in SelectQuizz.cshtml and QuizzTest.cshtml. To do that, from the Solution Explorer, expand the Views folder and right-click on Shared folder >> Add >> View. Don’t forget to check Create as a partial view option.

@using QuizApplicationMVC5.viewModels

@{
    UserVM userConnected = Session["UserConnected"] as UserVM;
    QuizVM quizSelected = Session["SelectedQuiz"] as QuizVM;
}

@if (userConnected != null)
{
    <div class="row">
        <div class="col-md-4">
            <img src="@string.Format("{0}{1}", Url.Content("~/images/"), userConnected.ProfilImage)" class="img-circle" style="width: 12%;" />
            <span><b>Welcome:</b> @userConnected.FullName</span>
        </div>

        <div class="col-md-4" style="margin-top: 15px;">
            @if (quizSelected != null && !string.IsNullOrEmpty(quizSelected.QuizName))
            {
                <span><b>Quiz Selected:</b> @quizSelected.QuizName</span>
            }
            else
            {
                <span><b>Please Select your Quiz</b></span>
            }
        </div>

        <div class="col-md-4" style="margin-top: 15px;">
            <span><b>Date:</b> @DateTime.Now</span>
        </div>
    </div>
}

Output

Now, our quiz application is ready. We can run and see the output in the browser.

Output

That’s all. Please send your feedback and queries in the comments box.


Similar Articles