Displaying a Grid of Data in ASP.NET MVC

Introduction

One of the most common tasks we face as a web developers is displaying data in a grid. In its simplest incarnation, a grid merely displays information about a set of
records - the orders placed by a particular customer, perhaps; however, most grids offer features like sorting, paging, and filtering to present the data in a more useful
and readable manner.

In ASP.NET WebForms the GridView control offers a quick and easy way to display
a set of records in a grid, and offers features like sorting, paging, editing, and deleting with just a little extra work. On page load, the GridView automatically
renders as an HTML <table> element, freeing you from having to write any markup and letting you focus instead on retrieving and binding the data
to display to the GridView. In an ASP.NET MVC application, however, developers are on the hook for generating the markup rendered
by each view. This task can be a bit daunting for developers new to ASP.NET MVC, especially those who have a background in WebForms.

This is the first in a series of articles that explore how to display grids in an ASP.NET MVC application. This installment starts with a walk through of creating the
ASP.NET MVC application and data access code used throughout this series. Next, it shows how to display a set of records in a simple grid. Future installments examine
how to create richer grids that include sorting, paging, filtering, and client-side enhancements. We'll also look at pre-built grid solutions, like the Grid component
in the MvcContrib project and JavaScript-based grids like jqGrid. But first
things first - let's create an ASP.NET MVC application and see how to display database records in a web page.

Read on to learn more!

Step 0: A Brief Roadmap

This article walks through creating an ASP.NET MVC 2.0 application in Visual Studio 2010 using C# and the default ASPX-style view engine. This project is used as the
demo application in this article and in the remaining articles in this series, and can be downloaded from the end of any article in the series. After creating the
ASP.NET MVC demo application, adding the Northwind database, and adding a data access layer using
Linq-to-SQL, we will look at how to display data in a simple grid. Future installments will build
atop the concepts presented in this article to add features like sorting, paging, filtering, and so on.

Step 1: Creating a New ASP.NET MVC Project

ASP.NET MVC is a Microsoft-supported framework for creating ASP.NET applications using a
Model-View-Controller pattern. In a nutshell, ASP.NET MVC allows developers much finer control over
the markup rendered by their web pages, a greater and clearer separation of concerns, better testability,
and cleaner, more SEO-friendly URLs. The ASP.NET MVC framework was first introduced in the days of Visual Studio 2008 and ASP.NET 3.5 SP1, and can still be
used in those earlier versions, although you'll need to download
and install it. The ASP.NET MVC framework was shipped as part of the .NET framework starting with .NET 4, so if you are using Visual Studio 2010 and ASP.NET 4
there is nothing extra you need to install or configure in order to start developing ASP.NET MVC applications.

Let's get started creating a new ASP.NET MVC application. Begin by launching Visual Studio and going to File -> New Project. Select the
ASP.NET MVC 2 Empty Web Application template; name the Solution GridDemosMVC and the Name of the project Web and click OK (see the screen shot below).

A new ASP.NET MVC project - even a so-called "empty" one - consists of a number of default files and folders:

Content - this folder is designed to contain static site content, such as CSS files, images, and so on.

Controllers - this folder will contain the application's Controllers. In MVC, the Controller is responsible for handling the incoming
request and choosing a Model and View to generate the response. Controllers are implemented as classes and their methods - which are referred to as
actions - are automatically invoked when a URL of the appropriate format is requested.

Models - this folder is used to hold the Models. Models are implemented as classes and contain the data and business
logic for a particular request.

Views - this folder holds the Views, which are responsible for generating the content returned to the requestor. Views typically contain
a mix of HTML, JavaScript, and server-side code. Unlike the WebForms model, where the server-side code is located in a separate code-behind class, with views the
server-side code and markup are placed in the same page and are intermingled. Moreover, the server-side code in Views is typically very simple, serving only to loop
through the data in the Model so as to generate the page's markup. A View's server-side code should not contain business logic.

Global.asax - behind the scenes, ASP.NET MVC uses ASP.NET Routing
extensively. By default, ASP.NET MVC applications contain a single routing rule that defines the following URL pattern:
{controller}/{action}/{id}. When a URL arrives
to the site, such as www.yoursite.com/Categories/View/Beverages,
ASP.NET MVC executes the controllerController class's action method, passing in
the id as an input parameter to the method. In the case of
www.yoursite.com/Categories/View/Beverages,
ASP.NET MVC would execute the CategoryController class's View method, passing in
the string Beverages as the input parameter to the method.

Before we start adding Controllers and Views, let's first get our Models and database squared away. The demos in this article series display data from the Northwind
database, which you can find in the download at the end of this article. Create an App_Data folder in your project and add the two database files,
northwnd.mdf and northwnd.ldf.

Now we need some way to access the data from the database. There are a variety of data access options available; for this article series I decided to go with
Linq-to-SQL, which is an object-relational mapping (O/RM) tool from Microsoft. I chose Linq-to-SQL
because it is, perhaps, the quickest and easiest O/RM to get started with. (I didn't want to get bogged down on the data access side since this article series
is aimed more at displaying data in a grid than it is at retrieving data from a database.) In a nutshell, using Linq-to-SQL entails adding a special file to our
project that specifies what database table(s) we need to access. Linq-to-SQL then creates classes that model these tables as well as a DataContext class
that is used to update and retrieve data to and from the database. Linq-to-SQL allows us to programmatically work with our database's data using terse, readable code
that is strongly-typed, meaning we get to enjoy compile-time type checking, IntelliSense, and so on. With Linq-to-SQL (or any O/RM, for that matter) there's no need waste
your time writing low-level ADO.NET code or craft SQL statements. If you are not familiar with Linq-to-SQL, or are just getting started, I highly recommend Scott Guthrie's
excellent tutorials on getting started with Linq-to-SQL.

Because we will be using the classes created by Linq-to-SQL as the Models in our application, add the Linq-to-SQL file to the Models folder. Specifically,
right-click on the Models folder and choose to add a new file. From the dialog box, select the LINQ to SQL Classes template and name the file
Northwind.dbml. This will create the new file and open it, showing you the Linq-to-SQL designer.

Next, go to the Server Explorer and expand the northwnd.mdf database. Drag both the Categories and Products tables onto the
design surface and then save your changes.

That's all there is to it! At this point we have our data access layer in place.

Step 3: Adding the Content Files to the Project

If you're following along from your computer, you should have the folders and files from when you first created the ASP.NET MVC application, as well as the App_Data and
the Northwind database files, and the Northwind.dbml file in the Models folder. There are a number of additional content files used in
the demo available for download at the end of this article, which include images and CSS files in the Content folder. Please take a moment to download the
demo application and copy the files from the demo's Content into your application's Content folder.

Also copy the demo's Site.Master file from the Views/Shared folder into your project's Views/Shared folder. The Site.Master file
is a master page for the application and defines the site-wide look and feel.

Do not copy over any other files and folders from the demo application - we'll be creating those ourselves in this article or in subsequent installments.

Step 4: Adding the ProductsController Controller

For this demo, all grid samples will fall under a single controller named ProductsController. For instance, the simple grid examined in this article will
be served from the Index action, meaning it will be accessible via www.yoursite.com/Products/Index (or just www.yoursite.com/Products,
since Index is the default action name), whereas the sorting and paging demos will be accessible via www.yoursite.com/Products/Sortable and
www.yoursite.com/Products/Paged.

To create a new Controller, right-click on the Controllers folder and choose Add -> Controller; name this new Controller ProductsController
and click Add. Doing so will create a new class named ProductsController with an Index method.

When a visitor reaches www.yoursite.com/Products/Index, we will display the name, category name, quantity per unit, price, and discontinued status for
all products in the Products table. To get this information we need to use the NorthwindDataContext class, which is one of the classes
auto-generated by the Linq-to-SQL tool. Because we'll need to work with the NorthwindDataContext class in all of the actions in this Controller, I decided
to add a property to the class named DataContext that returns an instance of this class. Additionally, this property configures the created
NorthwindDataContext instance so that it eager loads category information, since we'll often be displaying category details for each product.
(By default, Linq-to-SQL lazy loads related entities, meaning that if we get back a set of products , Linq-to-SQL
will go back to the database each time we access category information for a product (such as the product's category's name). If we know that we'll need the category
information for each product, it's more efficient to eagerly load it, meaning the category information is retrieved at the same time as getting the product information.
This saves us from having to go back to the database when accessing category information for a specific product.)

Add the following DataContext property related code to the ProductsController class:

The purpose of a Controller action is two-fold: to create the Model and determine what View to use to render the output. The return View() statement
handles the latter part - selecting the View - but we've yet to specify the Model. Because we want the View to display certain fields of all products, we can have the
Model simply be the set of Product objects in the database. This information can be retrieved using the following code:

var model = this.DataContext.Products;

But how do we get this Model to the View? There are two ways the Controller can pass the Model to the View:

Through the loosely-typed ViewData collection, or

By using a strongly-typed View.

The latter approach is preferred and is the technique we'll use. To send a strongly-typed Model to the view you simply pass is as the first argument to the
View method in the return statement. The code snippet below shows the updated code for the Index method.

Step 5: Creating the View

To create a View for the Index action, right-click on the method name and choose the Add View menu option. This will bring up the dialog box shown below.
Leave the View Name as Index, but check the "Create a strongly-typed view" checkbox and choose the Web.Models.Product class from the drop-down.
Check the "Select master page" checkbox if it is not already checked and use the ~/Views/Shared/Site.Master file as the master page. (Recall that you copied this file
from the demo application to your application back in Step 3.)

Adding this new View will create a Products subfolder and Index.aspx file within your Views folder. Take a moment to inspect
the View's @Page directive at the top. The Inherits attribute should specify the View's strongly-typed Model as Web.Models.Product.
Because the DataContext.Products property returns a collection of Product objects we need to change this to an enumeration of
Web.Models.Product objects. To accomplish this, modify the @Page directive so that it looks like the following:

At this point we're ready to construct the markup to be returned by the View. Because we are displaying a grid of data, let's use the HTML <table>
element to display the data. Start by adding a <table> element and a header row. As noted earlier, our grid is to display the name, category name,
quantity per unit, price, and discontinued status of each product. Consequently, our header row defined five columns.

The <table> has its class attribute set to grid - this is a CSS class definition in the sinorcaish-screen.css
file that defines certain formatting properties.

To display the data rows we need to loop through the set of Products in the Model. From within the View we can access the Model created by the Controller
by using the Model property. The following foreach loop enumerates each Product object in the Model and emits a table row.
Note how the String.Format method is used to format the UnitPrice as a currency. For the Discontinued column nothing is emitted if the
product is not discontinued, but for those that are an image - cancel.png - is displayed.

After the products have been displayed the markup is completed with the closing <table> tag.

If you visit the page through a browser - www.yoursite.com/Products or www.yoursite.com/Products/Index - you will see a nicely formatted
grid listing all of the products in the Northwind database.

Conclusion and Looking Forward...

This article showed how to create an ASP.NET MVC application and display data in a simple grid. With this foundation laid, we're ready to look at more interesting
and intricate grid examples. Future articles in this series will explore how to add sorting, paging, and filtering capabilities, as well as a look at using off the shelf
options, such as MvcContrib and jqGrid.