MVC 3 and the Razor View Engine

This beginner's tutorial is all about the Razor View Engine and MVC 3. You will be building a trivia game that simulates the world cup final. By completing this tutorial you will start to develop a basic understanding of MVC 3, build an understanding of the Razor View Engine and have some fun along the way.

The Razor View Engine is a syntax utilising .NET (C# or VB.NET) to build clean functional web pages using standard HTML.

Scott Guthrie sums up it up really well:

We had several design goals in mind as we prototyped and evaluated "Razor":

If you want to know about Razor have a look at Scott's blog post in full: http://weblogs.asp.net/scottgu/archive/2010/07/02/introducing-razor.aspx

This is one of my first applications built using MVC3 and I am sure I will be refactoring soon. I'll be posting further updates to this game on my blog at http://www.domscode.com/ so check there soon for the latest instalment.

Prerequisites

You will need VS2010 or Express Version and the latest version of MVC 3.0 (Including the recent Tools Update). Just go to http://www.asp.net/mvc and click on the MVC 3 Installer.

Whilst some knowledge of MVC would be really useful, there are lots of great resources out there to start including:

http://ASP.NET/MVC

http://websitesmaderight.com/2011/03/getting-started-with-asp-net-mvc/
http://weblogs.asp.net/jgalloway/archive/2011/03/17/asp-net-mvc-3-roundup-of-tutorials-videos-labs-and-other-assorted-training-materials.aspx

The Cricket World Cup 2011

First of all I must confess to being a cricket fanatic and If you can't get excited about the world cup of Cricket then what can you get excited about. Yes, unfortunately Australia did not win and my tears have filled my keyboard, but to be honest, my once mighty Aussies were not the same force they have been and despite Ricky Ponting's fine century against India in the quarter finals, Australia simply did not get enough runs. On the contrary India's success was based on a mighty top 6 batting line up and few teams rarely dismantled their top order. Well done India. It may be a bit harder in 2015 in OZ. Now back to the code....

The game

You play as India in the final and you will need to chase down a competitive target by correctly answering WC trivia cricket questions. You can select an easy, medium or hard question every over and an incorrect answer will mean a wicket has been lost or a correct answer means runs based on the following: easy: 2 runs an over, medium: 4 runs an over and hard:8 runs an over. You will notice when answering questions there are no spaces to enter and when you answer names surnames are all you need.

You'll notice I have only started with 30 questions but will be building this up in the future - feel free to add additional questions!!!

Let's get coding

This will create a basic starting MVC3 Project. First thing we need to do is get rid of some unnecessary files that are not of any use - they are mainly the account views and models.

The properties represent the attributes of the question class and you can see we are using data annotations for Answer and AttackLevel that enable us to facilitate the use of unobtrusive JavaScript a little later on when we create our views.

LoadQuestionsFromFile simply allows us to load the XML file into a collection of Questions.

Note in this class that the RandomQuestionsPerLevel (9) is for a 0 based array - so it refers to 10 items. In future versions I will replace the constant with a linq query to determine the questions per level.

Now we need to add our controllers. Let's start by adding the controller for the Questions. This is the key to our controllers because it is the director of all the logic within our Game. In general you will find that the controllers are the directors or facilitators of traffic in your MVC application.

There are two methods that we use in our controller. The first is:

public ActionResult Play(int? attackLevel)

This is called on a HTTP Get and you should think of it as the controller action that is called when the page is loaded or refreshed. We pass this method the Attack Level the user has entered so that when we display the question we load the appropriate question based on the Attack Level.

The second method (overloaded version of the first) is:

[HttpPost]
public ActionResult Play(Question question)


This method is only called on a HTTP Post from the form in the Game View that we will see in a moment. The attribute is needed to tell the controller that this method will only be called on a Post. We can see that we pass the Question model to this controllers action. Again in a moment we will see that this is the model that our view is bound to and is posted to the controller so that we can access that model within the controller.

Just before we create the views, we need a minor change to the index controller. So open the index controller and replace the existing code with:

using System.Web.Mvc;
using MVCCricketWorldCupTrivia.Models;

namespace MVCCricketWorldCupTrivia.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
Game game = new Game();
return View(game);
}
public ActionResult About()
{
return View();
}
}
}

Now there's a little bit going on here so I'll break it down.

First:

@model MVCCricketWorldCupTrivia.Models.Question

@{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}


This indicates that the model for this page is the Question model and we are also setting the View Title and the layout (similar to ASP.Net master pages).

Next:

<script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
<script src="../../Scripts/jquery.validate.js" type="text/javascript"></script>
<script src="../../Scripts/jquery.validate.unobtrusive.js"

type="text/javascript"></script>

<script type="text/javascript">
$(document).ready(function () {
$('#PlayersAnswer').focus();
});
</script
>


The scripts would normally be referenced in the /views/shared/_layout.cshtml, but I found that there was a problem with getting unobtrusive JavaScript to work without them in this view.

Then we have a neat snippet of jQuery that enables the focus on each page load to be the question answer textbox of the form.

Next:

<fieldset>
<h3>Scoreboard</h3>
<div class="Scoreboard">
@{if( Model!= null)
{
<div class="display-label">Sri LankaScore</div>
<div class="display-field">@Model.CurrentGame.SriLankaScore</div>

<div class="display-label">Wickets</div>
<div class="display-field">@Model.CurrentGame.Wickets</div>

<div class="display-label">Runs</div>
<div class="display-field">@Model.CurrentGame.Runs</div>

<div class="display-label">Overs</div>
<div class="display-field">@Model.CurrentGame.Overs</div>
}
}
</div>
</fieldset
>

This is just the scoreboard element of the view. Nothing really complex here; we just display all the important elements of the Models Current Game object. Although, we could potentially use a partial view here - I am just keeping things really simple and we'll get to partial views in future tutorials.

Finally:

@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<h3>Question</h3>

@Html.HiddenFor(m => m.QuestionID)

<div class="display-label">Question:</div>
<div class="display-field"> @Model.QuestionText </div>

@Html.LabelFor(model => model.PlayersAnswer)

<div class="editor-field" >
@Html.EditorFor(model => model.PlayersAnswer)
@Html.ValidationMessageFor(model => model.PlayersAnswer)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.AttackLevel)
</div>
<div class="editor-field" >
@Html.EditorFor(model => model.AttackLevel)
@Html.ValidationMessageFor(model => model.AttackLevel)
</div>
<p>
<input type="submit" value="Play" />
</p>
</fieldset>
}

So this is the main form for the View and contains all the important fields from the Game model class. Although it's a very simple piece of markup it provides
a lot of functionality through the Razor Engine and also built in validation via the models data annotations.
Also the/Views/Shared /_Layout.cshtml needs to be modified to include:
Now, We need to just add our final view. 
Of course we probably should be using a partial view here and removing the session in the view is also not great but for a tutorial it will do.

Just to add a nice black background to the scoreboard part of the view, let's change the main css file sightly.
The last thing we need to do is to add the XML file. You can find it with the sourcecode for this project (It will be residing in the model folder of the solution).
Save everything and now run the application (F5); you should see:

MVCWorldCup1.gif

Click on Play Game and you should see:

MVCWorldCup2.gif

Of course I was being optimistic and the scoreboard on the following screen shows the result:

MVCWorldCup3.gif

Terrible start really - One over down and a wicket already; this is an easier question:

MVCWorldCup4.gif

And we click Play:

MVCWorldCup5.gif

Now we are on the board with the chase but the run rate's a problem so let's increase the rate. Remember this will only take place after the next over
so the current question is still the easy one. So we answer this and enter the new attack level and click play.

MVCWorldCup6.gif

You can see below that now we have a harder question and the Attack Level has changed.

MVCWorldCup7.gif

So we answer SriLanka and then of course click play

MVCWorldCup8.gif

Ok we are starting to look good. I think you get the idea by now so let's fast forward to the end and the last ball...

MVCWorldCup9.gif

Click Play and of course with a winning score we get taken to the Complete View....

MVCWorldCup10.gif

So you should get the idea - it is a simple game and you can modify it as you need

In Conclusion:

OK so the game is pretty simple but you get the idea. If you feel like making some more changes a few things you could do would be:
I hope you have enjoyed this simple introduction to MVC 3 and well done again to the Indian cricket team for winning the 2011 world cup.

Dom

References

www.asp.net/mvc
http://weblogs.asp.net/scottgu/
http://www.hanselman.com/blog/