Monday, February 28, 2011

Dynamic Layout with MVC 3 and Razor

The past weekend has seen me at Sydney’s Webcamp.  It was a great 2 days of looking at some of Microsoft's Web Technologies as well as have a play with them in the labs.  Towards the end of the second day, after doing the labs I wanted to, I had a bit of a play wrote a simple site that changed it’s layout based on the querystring in MVC 3/Razor.  I thought I would share it with you.

First, make sure you have the MVC 3 templates, which you can get from Microsoft here.  These can take some time to install, so be patient.  You can also get it via the Web Platform Installer. (Note: I am working from Visual Studio 2010.  I am not sure of the compatibility of MVC 3 with previous versions of Visual Studio.)

Once that is installed, open Visual Studio, select File –> New –> Project.  Open the Visual C# set of Projects, select Web, and then select the ASP.NET MVC 3 Web Application.  Also, enter a name for the application (I have used MVC3DynamicLayout). Then hit OK.

The Project isn’t created yet.  On the next screen, you have the options around the type / template of MVC 3 Project to create.  For our purposes select the Empty Application and the Razor view engine.  Hit OK and your project will create.

So, we have our MVC 3 Project, now to get something that will execute.  Below is a picture of the file structure that we will use as a reference.

First, we create our initial layout.  Right click on the Shared folder (that is under the Views folder), select Add –> New Item.  Select the MVC 3 Layout Page (Razor) and enter site_1.cshtml as the Name.

This will create a new cshtml file, into which I have added some render sections and a <h1> tag to show that this is layout 1.  Note, the inline css is just to make the point of the exercise easier, not something you should do.

<!DOCTYPE html>

<html>
<head>
<title>@ViewBag.Title</title>
</head>
<body>
<div style="width:700px;">
<div style="border: red solid 1px;"><h1>This is layout one</h1></div>
<div style="border: green solid 1px;">
@RenderSection("Header",false)
</div>
<div>
<div style="width:100px; border: black solid 1px; float: left;">@RenderSection("Menu",false)</div>
<div style="width:596px; border: purple solid 1px; float: right;">@RenderBody()</div>
</div>
<div style="clear: both; border: blue solid 1px;">some footer text</div>
</div>
</body>
</html>

Now we need to add a controller.  So go to Controllers in Solution Explorer, right click and select Add –> Controller, and call it HomeController.  Do not select the check box to add action methods for create, update, delete and details scenarios.



And finally, we need to create the view to show with the correct layout.  In the home controller, right click anywhere in the Index function and select Add View.  Make sure you check the Use a layout or master page and have selected the site_1.cshtml layout that we have created.



Now, lets add the content to the view so that something is displayed.  That is in the code below.

@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/site_1.cshtml";
}

@section Header{
<h3>This is the head</h3>
}

@section Menu{
<ul><li>item 1</li><li>item 2</li></ul>
}

And here is the rendering of the body

Now, if you hit F5 you should get the following webpage.



So, at this stage you should have a working MVC 3 site, with some really cool looking layout and great UI. (OK, I joke… :D) But we are not done yet, that was only half of what we want.  Now for the other half, to be able to change the page layout dynamically.  Now, for our purpose dynamically will be a querystring value.


So, first lets create our second page layout. Right click on the Shared folder in the View folder, then add a new item.  As before, MVC 3 Layout Page (Razor) but this time enter site_2.cshtml as the Name.  Below is the code for site_2.cshtml

<!DOCTYPE html>

<html>
<head>
<title>@ViewBag.Title</title>
</head>
<body>
<div style="width:700px;">
<div style="border: green solid 1px;">
@RenderSection("Header",false)
</div>
<div style="border: red solid 1px;"><h1>This is layout two</h1></div>
<div>
<div style="width:596px; border: purple solid 1px; float: left;">@RenderBody()</div>
<div style="width:100px; border: black solid 1px; float: right;">@RenderSection("Menu",false)</div>
</div>
<div style="clear: both; border: blue solid 1px;">some footer text</div>
</div>
</body>
</html>

Now, we need to update the controller to accept the querystring argument and then, if that argument is a “y”, let the view know that it need to change the view layout.

    public ActionResult Index(string canIChangeTheLayout)
{
ViewBag.canIChangeTheLayout = (canIChangeTheLayout == "y")?"":"y";
ViewBag.Layout = "~/Views/Shared/site_1.cshtml";
if (canIChangeTheLayout == "y") ViewBag.Layout = "~/Views/Shared/site_2.cshtml";
return View();
}

And then need to make 2 changes to the view.  One to alter the layout (from the viewbag rather than hardcoded, and the other to create a link to control the querystring.  The new view code is below:

@{
ViewBag.Title = "Index";
Layout = ViewBag.Layout;
}

@section Header{
<h3>This is the head</h3>
}

@section Menu{
<ul><li>item 1</li><li>item 2</li></ul>
}

And here is the rendering of the body
<br /><br />
Link: @Html.ActionLink("change layout", "index", new { canIChangeTheLayout = ViewBag.canIChangeTheLayout })



And vola! If you click on the link you should alternate between the first layout and the layout below:



Well, I hoped you liked this basic review of the MVC 3 Projects and how to change the layout in code.

Tuesday, February 15, 2011

Test Driven Development

It has been some time since my last post, work has been rather hectic of late.  My downtime has been just that, downtime.  However when I finally got back to my Java oData Consumer I ended up having a good experience in Test Driven Development that I thought I would share.

The next small chunk that I wanted to complete was the XML namespace to package name piece, and then applying that package in my code when trying to get a type of node from a known namespace.  The first part was easy, I wrote my test, got the code working, and vola, I had my XML namespace to package converter.  Not the best work, has hardcoded parts that I would love to remove, but it does the job.  It is something I can refactor later once I have a complete oData consumer.  (A side note, I can add various namespaces and XML definitions easily, so am thinking of also expanding this to allow for a simple RSS consumer in Java, but that is way down the track and I digress.)

The next part I thought was simple. Combine the package name with the expected class name and end up with a complete class name that I can reference in my code when I am trying to create a new node in my tree.  I wrote my test, got it working, then because I had tests that checked the rest of the code I ran those and lo and behold they broke.  So, I fixed them up making sure that I was not breaking anything else, and my code went back to being robust.

The reason why I am saying that this is a good experience in Test Driven Development (TDD) is that if I did this the way I am used to, just manually tested my code, there is almost no chance that I would have picked up the bugs that I created.  By using TDD I had a repository of tests that I have coded against to meet the requirements (each in and of itself a small requirement).  Now I might not have hundreds and thousands of tests to run against my code, but as my codebase grows, the number of tests expands as well to cater for the new code.  No new code should be written where it isn’t to make a test pass.

However, proceed with caution here.  Tests need to be useful and meaningful.  Make sure that you are testing what you think your testing.  Your tests form part of your codebase, make sure you check that they pass regularly, and also make sure that you know what they are testing.  Having heaps of tests that are checking the same thing is pointless. If you have one test to check that your function is working in a set scenario, then move on.  You should write a new test for each scenario.  Also you when you get a bug you should be able to write a test to show that the bug is in the code, then you can debug your code to make sure that the fix is working, and that it hasn't accidently broken anything else.

A tip on testing that I got from Tatham Oddie (@tathamoddie on twitter) is to use the following template for writing a test.  It works in any language.  First create the test (the name and container in code).  Then add 3 comments: Arrange; Act; Assert.  The first part of your test should be to Arrange the objects that your testing, with mocks, creating the object that you want to test.  The second should be the Act part, this is where you perform the function or method that you want to test.  The third is the Assert part, where you check that what you wanted to be the result was indeed the result.