Introduction
With the release of MVC 3, the updated project templates and the Razor view engine, I wanted to see how hard it would be to get a quick mash-up of some ASP.NET goodness and the Google Maps API.
For this project, we're going to walkthrough creating a new project in ASP.NET using MVC 3 in Visual Studio 2010 then Razor-ify a very basic Google Map with a little bit of JavaScript.
Background
Though I touch lightly on some of the concepts of the MVC Framework in this article, for the most part I'll assume that you are comfortable with the pattern. Here are the bits you'll need to follow along:
How Things Have Changed
The Razor view engine is part of a new rendering framework for ASP.NET web pages. Unlike the classic ASP.NET rendering engine which uses opening and closing brackets to denote code (<% %
>), Razor allows a cleaner, implied syntax for determining where code blocks start and end.
In the classic renderer in ASP.NET, where you'd see something like this:
<ul>
<% foreach (var userTicket in Model)
{ %>
<li><%: userTicket.Value %></li>
<% } %>
</ul>
...you'd see something more akin to this in Razor:
<ul>
@foreach (var userTicket in Model)
{
<li>@userTicket.Value</li>
}
</ul>
There are also many other features that streamline development, such as Sections, Layouts and Razor-specific helpers. We'll explore those at a high level in this article.
MVC 3 Tooling Changes
Obviously with the new syntax comes changes to the way the templates are rendered. The tools have been updated accordingly and as a result we see much cleaner view sources when generating our views from the controller. For a view that's not strongly-typed, this is all we need to make the page tick:
Model inheritance is also significantly simplified and much more human readable. The way we've been doing it since MVC came out:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<Sample.Aspclassic.Models.StringModel>" %>
...and now in Razor:
@model IEnumerable<RazorMaps.Models.StringModel>
@{ ViewBag.Title = ""; }
We'll have a closer look at some of these features throughout the remainder of this text.
Getting Started
Once installed, it’s fairly easy to invoke the New Project dialog and select ASP.NET MVC 3 Web Application from the Web templates. If you don’t see the project type listed, make sure that you are targeting the correct framework.
I named my project RazorMaps. When we click ok, we are then presented with a bit of a wizard to select our options for the project. This is a simple but good improvement over the previous MVC bits because it rolls up the wizard, test project creation and multiple templates (empty versus the “internet application”) and lets us select the view engine.
For simplicity sake here, I’ve just selected an Empty template and no test project.
Most of the project pieces feel familiar, in fact, there’s no noticeable changes to the MVC project at a root level and all the expected folders are there.
It’s nice to see that jQuery is added by default to the _layout.cshtml
file, and to see that jQuery UI is included in the project.
As of my writing this, it’s also the latest bits for the jQuery library, and they have the vsdoc file updated (Sweet! No more renaming the old one and replacing the library!), and there are other libraries in the mix as well (enabling unobtrusive validation, etc.).
First, A Primer
You can skip to the next section if you are more interested in seeing it run than how it runs, but there are a couple of things that should be pointed out here, so that you're following along.
Razor has a minimal effect on the overall flow of an MVC application. Consider the juicy details of what is going on when a request is made to your app:
- Receive first request for the application
- Perform routing
- Create MVC request handler
- Create controller
- Execute controller
- Invoke action
- Execute result
from MSDN's Understanding MVC Application Execution
Basically, Razor kicks in at Execute result. Rather than using MasterPages for the template, Razor uses Layouts. Layouts, in the same vain as the syntax, are a simpler, cleaner way to put a template together for a web page. You need only to create an MVC application using each of the view engines to see this. Layouts also tend to read as more active in the rendering process; whereas in a MasterPage
, you would put in a ContentSection
to specify when content might be rendered, in a Layout
you make a call to RenderSection()
. Likewise, the sections are defined more like function calls in the content pages. We'll look at these differences as we implement the map.
Another difference is the way in which we look at PartialViews
. Razor uses the same file type, .cshtml, for partials and full views, whereas the classic MVC view engine used .ascx (user controls) to implement them. I don't suppose this is significant and there was no real reason to have to carry forth the old distinction.
One downside in the current tooling is that we lose Intellisense on styles and scripts in our views when we've specified JavaScript or CSS sources in our layouts. You can work around this by adding the references to each page (and there are a number of ways to avoid duplicate references if doing this).
So, with a little bit of background on some of the changes and where Razor fits in our paradigm, off we go!
A Simple Home Page
We need to get a view set up so that we have something to look at. The base project doesn't include the controller or the view we're going to want, so we'll start there.
Right-click on Controllers, Add > Controller and name it HomeController. We get our basic controller up-and-running and the code for our first ActionResult
(which will invoke the rendering of our home page) is free:
Next, right-click anywhere in the Index
method and select Add View from the context menu. If the View Name is Index
, then you shouldn’t need to change anything else. We’re using the Razor view engine and we already have our layout specified in _viewstart
.
Press F5 to see your lovely work!
Hello, Google Maps
We have a couple of things that we need to do to get the basic, no-frills map up-and-running. Though I worked from the simple tutorial on the Google Maps Javascript API page, I’m going to try to MVC this up as much as possible and look at some of the features of the Razor view engine.
We know that we need to add the Google Maps script to our page, and we can see from the tutorial that you also need to have a couple of styles. Because we are using layouts in Razor and don’t want these on every page we create, we’ll take advantage of Razor Sections in our layout.
Open up _Layout.cshtml
and add the following lines of code to the <head>
portion of the document:
<pre lang="aspnet">@RenderSection("Scripts", false)
<style type="text/css">
@RenderSection("Styles", false)
</style>
We’re adding two optional RenderSections
here. This is very similar to creating content sections when using master pages.
Next, pop back into our index.cshtml
file so that we can add the juicy bits to get the map loading. At this point, it's worth grabbing one of those cookies.
Fleshing Out the Page
Right at the top of the file, you’re going to want to add the following code:
@{
ViewBag.Title = "MVC 3 and Google Maps";
}
@section Scripts {
<script type="text/javascript"
src="http://maps.google.com/maps/api/js?sensor=false"></script>
}
@section Styles {
html { height: 100% }
body { height: 100%; margin: 0px; padding: 0px }
#map_canvas { height: 80% }
}
The ViewBag
is a dynamic expression that gets evaluated at runtime. The "Title
" property is filled into our layout template with the @ViewBag.Title
expression.
Next, we have our two sections; the first adds the map script to our page, the second applies and specifies the styles we need to get the map rendering correctly.
The rest of the page consists of:
- A
div
element (to host the map)
- An
initialize
function that sets up the map, and
- A jQuery shortcut to invoke the initialize function when the page is ready
Here’s the code:
<h2>Hello, Google Maps</h2>
<div id="map_canvas" style="width:80%; height:80%"></div>
<script type="text/javascript">
function initialize() {
var latlng = new google.maps.LatLng(40.716948, -74.003563);
var options = { zoom: 14, center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP};
var map = new google.maps.Map(document.getElementById
("map_canvas"), options);
}
$(function () {
initialize();
});
</script>
And there you have it! Press F5 again and the map loads.
Conclusion
If you have a good handle on ASP.NET MVC and you understand MasterPage
s, the switch to the Razor engine and templates is going to be easy and refreshing. Integrating per-page code, via Razor section rendering, is straightforward and keeps our templates clean.
Updated script libraries and improved templates and a ton of feature enhancements round out this release nicely.
Here are some links and helpful references to get you plugged in to related content:
History
- 2011-01-21.1: First version
- 2011-01-21.2: Uploaded application image
- 2011-01-21.3: Added Google Maps link
- 2011-01-21.4: Added more background on Razor (thanks Pete!)
- 2011-01-21.5: Added more information on tooling
- 2011-01-26.1: Added primer, MSDN link in references