ASP.NET MVC Example with Northwind and Entity Framework Published
The Microsoft ASP.NET MVC Framework was released as a CTP as part of the ASP.NET 3.5 Extensions Preview a short time ago. Since that time the MVC Framework has gotten a lot of attention in blogs and developer-focused web sites.
Brad Abrams,
founding member of the CLR and .NET Framework teams at Microsoft,
published a good example of how developers can leverage the MVC
Framework with some of the new tools from Microsoft. The example
originated from the MVC example Scott Guthrie put together on his blog
demonstrating how the MVC Framework, in its initial form, works.
Scott's example is documented very well and can be seen in four parts:
The MVC Framework gives developers the flexibility to chose both the
view and model engines to suite their needs. In Scott's example he is
using LINQ to SQL models but Brad decides to use the Entity Framework
instead, using the Northwind database as the the data source.
Developers can choose from many different model providers, for example:
We should see other model providers in the future as well, possibly:
Brad's approach to creating the example leads the developer from the
start of the project using the ASP.NET MVC Application and Test.
Developers will need to have the following installed:
The Tutorial
The tutorial is rather extensive and is worth looking through
carefully to get the full benefits of how the MVC Framework functions
and ties everything together. Using MVC is very different than your
everyday Web Forms application and will take some getting used to by
even seasoned ASP.NET Web Form developers.
Getting Started
Once the ASP.NET 3.5 Extensions are installed there are a few more
project types to choose from including ASP.NET MVC Web Application and
ASP.NET MVC Web Application and Test. The ASP.NET Framework is
designed to be tested, Brad uses testing.
File/New Project - Select ASP.NET MVC Web Application and Test
This creates a single solution with both a web application project
as well as a project we can use for unit testing. Both are
pre-populated with the basic stuff you need to get going.
Creating the Routes
Routing in an MVC Framework is one of the more interesting aspects
of the design. This is where the developer gets to decide how their
pages are found by the application. In the classic ASP.NET application
a page such as home.aspx has a very clear way to get to the page, often
something like www.mywebsite.com/home.aspx. Routing gives the developer a lot of flexibility over this.
One of the powerful new features that ASP.NET MVC brings to the
table is the ability to customize the URLs that access your
application. The URL routing feature explicitly breaks the connection
between physical files on disk and the URL that is used to access a
given bit of functionality. This is important for Search Engine
Optimization as well as general usability of the website. For
example, rather than access http://localhost/Products/ItemDetails.aspx?item=42 you can now very give a pretty URL such as http://localhost/Products/CodFishOil
This is done by creating a route table in the global.asax file in
the MVC Application. Luckily for us, the defaults included in the
template work perfectly this application.
RouteTable.Routes.Add(new Route
{
Url = "[controller]/[action]/[id]",
Defaults = new { action = "Index", id = (string)null },
RouteHandler = typeof(MvcRouteHandler)
});
This code spells out the format of the URLs we want to use for our site. In particular, a URL of the format
http://localhost/Products/Details/CodFishOil
would translate to the ProductsController class (notice we add the
"Controller" suffix to the class name to make these classes stand out
in the object model at design time). Then the Action is a method on
that class called Details and finally the argument to that details
method is CodFishOil.
It is of course possible to have other formats, simply by changing he regular expression in the URL pattern string.
Creating the Model
The model is the heart of most web applications, almost all have
some kind of data store behind them. The MVC Framework gives
developers almost unlimited ability to use any data source and the
ability to easily interchange between them.
The model represents the data you are going to use in the
application. In our case, this is a pretty good place to start the
core of the application.
In the App_Data direction of the MVCApplication copy the
Northwind.mdf file. Northwind is likely the most common example
database we have for SqlServer... You can download it from the official location, or for just the raw file, feel free to grab it from here.
Next, we need to create a LINQ model on top of northwind to make it easier to work with... You can do this with NHibernate, LinqToSql, Entity Framework , or any other .NET OR-Mapping
technology. As long as it results in .NET Object, the ASP.NET MVC
framework can work with it. In this case I am going to use the Entity
Framework.
Right click on the Models directory and select add new item
In the dialog select ADO.NET Entity Data Model.
In the wizard, select "Generate from Database" and then go with the default "Northwnd" connection string.
For our demo, we are only going to use the Categories, Products and
Suppliers tables, but you could of course extend this demo to include a
richer feature set. But for now, unselect the Views and Stored
Procedures and all the tables except those three..
When you click finished, VS will create a set of .NET classes that
are custom built for accessing this database and we get a nice designer
for visualizing the data relationships.
Notice, that the default names given to these classes still use the
plural names from the database, but in our OR-Mapping they represent
single instances, so to make the code easier to read, go in and change
all the table names to their appropriate singular form: Category,
Product and Supplier. Then Navigation properties on Product needs to
be singular as there is only one Category and Suppler for each product.
Next we need to cleanup the namespace so things look pretty in our
code... Right click on the design surface then set the properties such
that namespace is "NorthwindModels" and the Entity Container name to
"NorthWindEntities"
While we are not 100% done with the model, we have gotten the lion's
share of it complete.. Let's switch over and look at the controller.
Creating the Controller
The controller is the brains behind our application. Think of the
controller as the air traffic controller at an airport, giving
direction to the coming and going of aircraft. The controller is in
charge of taking data in one hand and handing it off to the view in the
other.
Right click on the Controller directory and select "Add new Item".
In the dialog find MVC Controller and be sure to give it a name that
ends in the Controller suffix. In our case we are writing the
ProductsController.
OK, we are ready to start working in ProductsController.cs
The goal of the controller is to prepare the model for the view.
We want to bring as much logical as possible out of the view because it
is so hard to test in the view. So in the controller, we are going to
be accessing the Model and getting it all set up so all the view has to
do is spit out some data.
The first thing we need, is access to our database.
1. Add the right namespaces... Linq and a reference to our OR mapping.
using System.Linq;
using NorthwindModel;
2. Next, we create an instance of the NorthwindEntities container class. Nearly all of our actions will access this class.
public class ProductsController : Controller
{
NorthwindEntities Northwind = new NorthwindEntities();
OK, now we are ready to create our first action.. Listing all the
categories. Remember the job of the controller is to prepare the model
for the view.. When defining a new action, I like to start off by
putting a comment that reminds me what the URL is that access this
functionality.
The next thing we do is access the Categories table from the model.
I snap the results to a generic collection class (you may have to add a
reference to System.Collections.Generic) then we pass the results to
the view named "Categories". This is a very simple example, later we
will see more complex logic here.
//URL: http://localhost/Products/Categories
[ControllerAction]
public void Categories()
{
List categories = Northwind.Categories.ToList();
RenderView("Categories", categories);
}
Next step, we need to create the "Categories" view..
Creating the View
The MVC Framework gives the developer almost as much flexibility
here as with models. Developers can choose from an array of view
engines and interchange them as well.
Right click on the Views folder, add new Directory "Products". This
so we can organize all our views cleanly. The Right click on
Views/Products folder and add new item MVC View Content Page. We are
going to leverage the Master Page that comes with the default project
to make this look a little more pretty.

Call it Categories.aspx... It is important that the view name matches the first argument to the RenderView method above.
The default project puts the master page in Views/Shared/Site.Master

In order to get the strongly typed access to the ViewData we are
passing in from the controller, we need to tell the View Page, the type
to expect. This is done by opening up the codebehind
(Categories.aspx.cs) and changing the derived type from:
public partial class Categories : ViewPage
{
}
to:
public partial class Categories : ViewPage< List >
{
}
Then you simply write clean, simple, designable HTML. Notice here I
am looping over all the items returned in ViewData and pushing them out
as a link. I use the MVC helper method Html.ActionLink to create the
URL for the List action with the appropriate product ID.
Browse Products
<% foreach (var category in ViewData) { %>
<%= Html.ActionLink(category.CategoryName, new { action="List", id=category.CategoryName }) %>
<% } %>
OK, we are finally ready to run it!
Hit F5, and navigate to the controller action we just wrote on http://localhost:64701/products/Categories

Clicking on any of the links give you an error, because we haven't written the List action yet.. we will do that next.
As an aside, if like me, you are in the habit of using "View in
Browser" on aspx pages you develop, you are likely to see this error.
To reproduce, right click on Categories.aspx and select View in
browser.

You get an error. Why? Well, remember with the MVC model, all
execution goes through the controller, the views themselves are not
runnable. Future tooling will make this better, but in the mean time,
use F5 or you can "run in browser" with default.aspx.. just be sure you
have built the solution first!
The List Action View
OK, let's now go back and add the List action that we are missing.
What we need to do here is find all the products with a give
Category. First I need to get all the products out of the model, then
I need to ensure that the Category references are loaded. The entity
framework offers an explicit loading model by default. As such you
have to explicitly load any tables you need. And finally we render the
view.
//example URL:http://localhost:64701/products/List/Confections
[ControllerAction]
public void List(string id)
{
List products = Northwind.GetProductsByCategory(id);
//prepare the view by explicitly loading the categories
products.FindAll(p => p.Category == null).ForEach(p => p.CategoryReference.Load());
RenderView("ListingByCategory", products);
}
Notice, i am calling a custom method on the NorthwindDataContext
class... Personally I like the idea of keeping all the data access
logic encapsulated in that class. So to define this method, Right
click on the Model, add new Item, select CodeFile and name it
NorthwindDataContext.cs and give it the implementation.
using System;
using System.Collections.Generic;
using System.Linq;
namespace NorthwindModel
{
public partial class NorthwindEntities
{
}
}
Now you can easily add data access methods to this class... such as the GetProductsByCategory() method we use above.
public List GetProductsByCategory(string category)
{
return Products.Where(p => p.Category.CategoryName == category).ToList();
}
Next, we need to add the ListingByCategory view... We follow the
same steps from above to add a ListingByCategory.aspx page in the
Views/Products/ directory.
This time, we should make the ViewData be of type List
public partial class ListingByCategory : ViewPage< List >
{
}
Next, to implement the view, we simply loop over the view data and spit it out in the right format.
<%--Print out the catagory name--%>
<% foreach (var product in ViewData) { %>
<% if (product.Category.CategoryName != null) { %>
<%=product.Category.CategoryName %>
<% break; %>
<%} //end if %>
<%}//end foreach %>
<% foreach (var product in ViewData) { %>
<%=product.ProductName %>
Price: <%=String.Format("{0:C2}", product.UnitPrice)%>
(<%= Html.ActionLink("Edit", new { Action="Edit", ID=product.ProductID })%>)
<% } %>
Once you add the /Content/Images directory from the sample project you get this:

Brad's example is in C# so Julie Lerman chose to create Brad's example her own way using VB.NET and the AdventureWorksLT database
and focusing on more efficient Entity Framework queries. Julie points
out some important factors of her implementation over Brad's.
- My EDM is created from AdventureWorksLT.
- The
relationship from AW's SalesOrderHeaders to Customer is the same as the
relationship from Northwind's Products to Category. Therefore, where he
use Products, I use SalesOrderHeaders and where he uses Categories, I
use Customers.
- One of the keys for getting data
easily to a view is that we need to send ONE object (and not an
anonymous type) to the view. Yet what we really desire in the case of
the List of Order (which also has the Customer Name) and the list of
details (which also has data from the order and the customer) is an
object graph.
Those developers who would rather just download the completed application and not have to go through the process step-by-step can download the working example from Brad's blog.