Displaying a list of distinct countries of F1 racers within an HTML select element, and displaying a list of racers from one specific country has been the topic for the previous blog posts of this series. Previously this was done with ASP.NET Web Forms and ASP.NET Web Pages. The last article of this series demonstrates the same with ASP.NET MVC.
ASP.NET MVC is one of the newer ASP.NET technologies to create Web applications. Here I’m using version 3 which is an update to the version that is delivered with Visual Studio 2010. ASP.NET MVC is based on the model-view-controller pattern to make a separation between the view and the functionality. This separation helps with unit tests.
For a start I’m creating a new ASP.NET MVC Project using the Empty template. With the MVC3 templates it’s already possible to select HTML5 semantic markup with the template, and of course the Razor engine. Razor was already used with the previous blog post on Filter and display data with ASP.NET Web Pages as can be seen in the following figure.
The Empty project template already creates the main structure of the application with Models, Views, and Controllers directories, and JQuery scripts are also available with the project. MVC 3 contains version 1.5.1 of JQuery. A newer version is already available that can be loaded with the Visual Studio 2010 Extension Manager. However, for the simple scenario of this blog article an update is not required.
Routes
With the Empty template the global.asax file is already filled with some code. An important aspect of ASP.MVC is that the client doesn’t directly request the ASPX pages from the server, instead routing is done. The route is defined within global.asax in the method RegisterRoutes. With the generated code you can see an invocation to the MapRoute method that defines the Default route. The route is defined by {controller}/{action}/{id} with the default Home/Index/optional. The default means that if controller and action is not specified, the request to the Web application is directed to the Home controller with the Index action.
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults ); }
The controller and action will be specified later. Before implementing the controller some data is needed.
Model
The entity types and data context classes to access the database is created with the help of the ADO.NET Entity Framework within the Models directory. Adding an ADO.NET Entity Data Model to the Models directory, generating the model contents from the database, and selecting the Racers table from the Formula1 database opens the designer showing the Racer type as in the following figure.
Controller
A method of a controller is invoked on a client request. Controller classes are defined within the Controllers directory. The Controller class i postfixed with the name Controller, such as the Home controller has the name HomeController. With definition of the routes you’ve seen that the default controller is the HomeController.
With the ASP.NET MVC 3 templates it’s easy to create controllers by using the Add Controller template. This template can create some implementation of the controller depending on the scaffolding options selected. First I’m showing the option to create read/write actions using the Entity Framework. With this option a model class can be selected (an entity type with the Entity Framework), and the data context class.
The generated controller class includes methods to retrieve a list of all racers, a single racer by passing the identifier, and also methods to create, edit, and delete racers.
public class HomeController : Controller { private Formula1Entities db = new Formula1Entities(); // // GET: /Home/ public ViewResult Index() { return View(db.Racers.ToList()); } // // GET: /Home/Details/5 public ViewResult Details(int id) { Racer racer = db.Racers.Single(r => r.Id == id); return View(racer); }
Another option of the template is to create a controller that contains read/write actions, but without implementation. For the sample I’m starting here with the third option to create an empty controller. This creates the HomeController class with an Index method as shown.
public class HomeController : Controller { // // GET: /Home/ public ActionResult Index() { return View(); } }
For accessing the database with the Entity Framework datacontext an instance of the Formula1Entitiies class is created and disposed.
private Formula1Entities db = new Formula1Entities(); protected override void Dispose(bool disposing) { db.Dispose(); base.Dispose(disposing); }
The first action demonstrated should return a list of racers depending on the country passed with the link, e.g. the query http://<server>/RacersByCountry/USA should return the racers from the USA. The action has the name RacersByCountry. The parameter has the name id as is defined by the parameter with the routing definition within global.asax. Returned from the action method is a ViewResult. Action methods from a controller can return a type that derives from ActionResult. Examples are JavaScriptResult to return JavaScript code, JSonResult to return a JSON object, RedirectResult to do a HTTP Redirect. To return a view, the return type is ViewResult. Partial views can be returned with the type PartialViewResult. The action RacersByCountry should return a complete view, thus the return type is defined as ViewResult. Returning a ViewResult, the View method of the Controller type is used. The View method accepts the name of the view that should be returned. If the name of the view is not passed, a view with the name of the action is selected. Another parameter of the View method is of type object where a model can be passed. This model can then be used by the view for displaying data. The sample passes a model where racers from the data context are filtered by the country.
public ViewResult RacersByCountry(string id) { return View( db.Racers.Where(r => r.Country == id).ToList()); }
View
After defining the controller it’s possible to define a view. Visual Studio templates take some work over creating the view. Selecting the Home directory inside the View (Home is the name of the controller), clicking the context menu Add | View… a new view can be created as shown in the following figure.
The first line of the generated view lists the model directive. This directive is new with ASP.NET MVC 3 to have a shorter notation of deriving from the base class passing the generic type for using strongly-typed model classes within the view. The longer term would be @inherits System.Web.Mvc.WebViewPage<IEnumerable<MvcDataQuery>>. In case a different base class should be used, the model directive is still possible. In such a case the base class can be configured in the configuration file. The Title of the ViewBag is set to be used within the shared layout page to set the HTML title element.
@model IEnumerable<MvcDataQuery.Content.Racer> @{ ViewBag.Title = "Racers by Country"; }
Following in the page is a HTML table with heading information. The Visual Studio template takes the properties of the model type to define the headings.
<table> <tr> <th> Firstname </th> <th> Lastname </th> <th> Country </th> <th> Starts </th> <th> Wins </th> </tr>
Every item in the model is iterated with a foreach statement. The value of every property of the item is displayed with the DisplayFor method of the HTML helper class. This method returns a string for primitive types, for Boolean values a HTML checkbox is returned.
@foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Firstname) </td> <td> @Html.DisplayFor(modelItem => item.Lastname) </td> <td> @Html.DisplayFor(modelItem => item.Country) </td> <td> @Html.DisplayFor(modelItem => item.Starts) </td> <td> @Html.DisplayFor(modelItem => item.Wins) </td> </tr> }
Running the application passing a country followed on the action returns the filtered racers.
Christian
The next article in this series continues with ASP.NET MVC and adds a selection element to select available countries before displaying racers.
More information on ASP.NET MVC is available with my workshops.
Comments
You can follow this conversation by subscribing to the comment feed for this post.