Entries Tagged 'MVC' ↓

MIX08

MIX is a Microsoft web development conference we hold in Las Vegas each year. 

MIX tends to be a pretty fun event, both because it covers cutting edge content (we used MIX07 to announce our Silverlight plans), and also because it tends to attract a really diverse set of attendees (including both those who use Microsoft technology today, and a large % of attendees who don't).  The conference structure includes a healthy blend of sessions and interactive panels, and the layout and organization is designed to facilitate great conversations.

This year's MIX is being held March 5th-7th in Las Vegas.  Ray Ozzie and I are both giving keynotes the first day of the event, and Steve Ballmer and Guy Kawasaki will be doing a keynote the second day of the event.

The conference (and especially my keynote) is going to cover a lot of new web technology.  Attendees will be able to attend sessions covering:

  • IE 8
  • IIS 7.0
  • ASP.NET (including ASP.NET 3.5, ASP.NET AJAX, ASP.NET MVC, and ASP.NET Dynamic Data) 
  • VS 2008 and Expression Studio
  • WPF
  • Silverlight 2
  • And much more....

Channel 9 recently did an interview with me where I talked about some of these new technologies.  In Part 1 of the interview I talked about IIS7, and in Part 2 of the interview I talked about ASP.NET, WPF and Silverlight 2.

Register Soon Or You'll Miss Your Chance

MIX is held at a smaller venue then some of our larger events like TechEd and PDC.  This gives the conference a more intimate feel (which is fun).  It also means that it sells out each year, and once it is sold out it is really sold out. 

Last year I received about 50 emails from people begging for tickets after it was full, and many people even flew to the event hoping to somehow be let in at the door (only to be unfortunately told they couldn't get in).  Unfortunately because of size constraints (and fire marshal restrictions) once it is sold out there really are no more tickets to be had.  Even my own team members get turned away if they haven't registered in time.

This year's registration is filling up faster than any of the previous MIX conferences.  If you want to attend I highly recommend registering really soon to ensure you can go.  You can learn more about the event and register online here.

Hope to see some of you there - it is going to be fun....

Scott

ASP.NET 3.5 Extensions CTP Preview Released

Earlier today we released the first CTP preview of an "ASP.NET 3.5 Extensions" release that we've been working on (click here to read my previous post about our product roadmap).  This release brings additional runtime functionality to ASP.NET and .NET 3.5.  You can download it here (if you are using the MVC features also click here to download the MVC Toolkit extras).

This first ASP.NET 3.5 Extensions preview release includes:

  • ASP.NET AJAX Improvements: New ASP.NET AJAX features in the ASP.NET 3.5 Extensions release include better browser history support (back/forward button integration, and server-side history management support), improved AJAX content linking support with permalinks, and additional JavaScript library improvements.
  • ASP.NET MVC: This model view controller (MVC) framework for ASP.NET provides a structured model that enables a clear separation of concerns within web applications, and makes it easier to unit test your code and support a TDD workflow. It also helps provide more control over the URLs you publish in your applications, and more control over the HTML that is emitted from them.
  • ASP.NET Dynamic Data Support: The ASP.NET 3.5 Extensions release delivers new features that enable faster creation of data driven web sites.  It provides a rich scaffolding framework, and will enable rapid data driven site development using both ASP.NET WebForms and ASP.NET MVC.
  • ASP.NET Silverlight Support: With the ASP.NET 3.5 Extensions release we'll deliver support for easily integrating Silverlight within your ASP.NET applications.  Included will be new controls that make it easy to integrate Silverlight video/media and interactive content within your sites.
  • ADO.NET Data Services: In parallel with the ASP.NET Extensions release we will also be releasing the ADO.NET Entity Framework.  This provides a modeling framework that enables developers to define a conceptual model of a database schema that closely aligns to a real world view of the information.  We will also be shipping a new set of data services (codename "Astoria") that make it easy to expose REST based API endpoints from within your ASP.NET applications.

We will be publishing many blog posts and videos discussing the new features in the weeks and months ahead.  Click here to check out an initial set of Quickstart Samples that cover some of the new preview features. 

Below you can find links to a few tutorial posts I've done (and a cool screencast by Scott Hanselman and some great testing tutorials by Phil Haack) that cover the new ASP.NET MVC Framework option.  I'll be doing more posts on the non-MVC features in the extensions release in the weeks ahead as well:

To ask questions or get help, please visit these forums on http://forums.asp.net

Hope this helps,

Scott

ASP.NET MVC Framework (Part 4): Handling Form Edit and Post Scenarios

The last few weeks I have been working on a series of blog posts that cover the new ASP.NET MVC Framework we are working on.  The ASP.NET MVC Framework is an optional approach you can use to structure your ASP.NET web applications to have a clear separation of concerns, and make it easier to unit test your code and support a TDD workflow.

The first post in this series built a simple e-commerce product listing/browsing site.  It covered the high-level concepts behind MVC, and demonstrated how to create a new ASP.NET MVC project from scratch to implement and test this e-commerce product listing functionality.  The second post drilled deep into the URL routing architecture of the ASP.NET MVC framework, and discussed both how it worked as well as how you can handle more advanced URL routing scenarios with it.  The third post discussed how Controllers interact with Views, and specifically covered ways you can pass view data from a Controller to a View in order to render a response back to a client.

In today's blog post I'm going to discuss approaches you can use to handle form input and post scenarios using the MVC framework, as well as talk about some of the HTML Helper extension methods you can use with it to make data editing scenarios easier.  Click here to download the source code for the completed application we are going to build below to explain these concepts.

Form Input and Post Scenario

To help illustrate some of the basics of how to handle form input and posting scenarios with the ASP.NET MVC Framework, we are going to build a simple product listing, product creation, and product editing scenario.  It will have three core end-user experiences:

Product Listing By Category

Users will be able to see a listing of all products within a particular product category by navigating to the /Products/Category/[CategoryID] URL:

Add New Product

Users will be able to add a new product to the store by clicking the "Add New Product" link above.  This takes them to the /Products/New URL - where they will be prompted to enter details about a new product to add:

When they hit save, the product will be added to the database, and they will be redirected back to the product listing page.

Edit Product

On the product listing page users can click the "Edit" link next to each product.  This takes them to the /Products/Edit/[ProductID] URL - where they can change the product details and hit the Save button in order to update them in the database:

Our Data Model

We are going to use the SQL Server Northwind Sample Database to store our data.  We'll then use the LINQ to SQL object relational mapper (ORM) built-into .NET 3.5 to model the Product, Category, and Supplier objects that represent rows in our database tables. 

We'll begin by right-clicking on our /Models sub-folder in our ASP.NET MVC project, and select "Add New Item" -> "LINQ to SQL Classes" to bring up the LINQ to SQL ORM designer and model our data objects:

We'll then create a partial NorthwindDataContext class in our project and add some helper methods to it.  We are defining these helper methods for two reasons: 1) it avoids us embedding our LINQ queries directly in our Controller classes, and 2) it will enable us to more easily adapt our Controller to use dependency injection in the future.

The NorthwindDataContext helper methods we'll add look like below:

To learn more about LINQ and LINQ to SQL, please check out my LINQ to SQL series here.

Building Our ProductsController

We are going to implement all three of our core end-user browsing experiences using a single controller class - which we'll call "ProductsController" (right click on the "Controllers" sub folder and select "Add New Item" -> "MVC Controller" in order to create it:

Our ProductsController class will handle URLs like /Products/Category/3, /Products/New, and /Products/Edit/5 by implementing "Category", "New", and "Edit" actions:

Read Part 1 and Part 2 of my ASP.NET MVC Series to learn more about how these URLs are routed to the action methods on the ProductsController class.  For this sample we are going to use the default /[Controller]/[Action]/[Id] route mapping rule - which means we do not need to configure anything in order for the routing to happen.

Our Controller actions will be using three View pages in order to render output.  The "List.aspx", "New.aspx", and "Edit.aspx" pages will live under the \Views\Products sub-folder, and be based on the Site.Master master page under \Views\Shared.

Implementing Product Listing By Category

The first part of the site that we'll implement will be the Product Listing URL (/Products/Category/[CategoryId]):

We'll implement this functionality using the "Category" action on our ProductsController class.  We'll use our LINQ to SQL DataContext class, and the GetCategoryById helper method we added to it, to retrieve a Category object that represents the particular category indicated by the URL (for example: /Products/Category/3).  We'll then pass the Category object to the "List" view to render a response from it:

When implementing our List view we'll first update our page's code-behind to derive from ViewPage<Category> so that our page's ViewData property will be typed to the Category object that was passed by our Controller (Part 3 discusses this more):

We'll then implement our List.aspx like below:

The above view renders the Category name at the top of the page, and then renders a bulleted list of the Products within the category. 

Next to each product in the bulleted list is an "Edit" link.  We are using the Html.ActionLink helper method that I discussed in Part 2 to render a HTML hyperlink (for example: <a href="/Products/Edit/4">Edit</a>) that when pressed will navigate the user to the "Edit" action.  We are also then using the Html.ActionLink helper method again at the bottom of the page to render a <a href="/Products/New">Add New Product</a> link that when pressed will navigate the user to the "New" action.

When we visit the /Products/Category/1 URL and do a view-source in the browser, you'll notice that our ASP.NET MVC application has emitted very clean HTML and URL markup:

Implementing Add New Product (Part 1 - Background)

Let's now implement the "Add New Product" form post functionality of our site.  We'll ultimately want users to see a screen like below when they visit the /Products/New URL:

Form input and editing scenarios are typically handled in the ASP.NET MVC Framework by exposing two Action methods on a Controller class.  The first Controller Action method is responsible for sending down the HTML containing the initial form to display.  The second Controller action method is then responsible for handling any form submissions sent back from the browser.

For example, for our "Add Product" screen above we could choose to implement it across two different ProductsController actions: one called "New" and one called "Create".  The /Products/New URL would be responsible for displaying an empty form with HTML textboxes and drop-down list controls to enter new product details.  The HTML <form> element on this page would then have its "action" attribute set to the /Products/Create URLThis means that when the user presses a form submit button on it, the form inputs will be sent to the "Create" action to process and update the database with.

Implementing Add New Product (Part 2 - First Approach)

Below is an initial implementation that we could use for our ProductsController. 

Notice above that we now have two action methods involved in the product creation process - "New" and "Create".  The "New" action method simply displays a blank form to the user.  The "Create" action method is what processes the posted values from the form, creates a new Product in the database based on them, and then redirects the client to the category listing page for the product.

The HTML form sent to the client is implemented in the "New.aspx" view called by the "New" action method.  An initial implementation of this (using textboxes for everything) would look like below:

Note above how we are using a standard HTML <form> element on the page (not a form runat=server).  The form's "action" attribute is set to post to our "Create" action method on ProductsController.  The post will happen when the <input type="submit"> element at the bottom is pressed.  When this happens, the ASP.NET MVC Framework will automatically handle mapping the ProductName, CategoryID, SupplierID and UnitPrice values as method parameters to the "Create" action method on ProductsController:

And now when we run the site we have basic product entry functionality working:

Implementing Add New Product (Part 3 - Using HTML Helpers for Drop Down Lists)

The product entry screen we created in the previous section works, but isn't very user friendly.  Specifically, it requires that the end user know the raw CategoryID and SupplierID numbers for the Product being entered.  We need to fix this by instead displaying an HTML dropdownlist that displays the human readable names.

Our first step will be to modify our ProductsController to pass to the View two collections - one containing a list of available categories, the other a list of available suppliers.  We'll do this by creating a strongly typed ProductsNewViewData class that encapsulates these, and which we'll then pass to the View (you can learn about this in Part 3):

We'll then update our "New" action method to populate these collections and pass them as the ViewData for the "New" view:

Within our view we can then use these collections to generate HTML <select> dropdowns. 

ASP.NET MVC HTML Helpers

One approach we could use to generate our dropdowns would be to manually create our own <% %> for-loop containing if/else statements within the HTML.  This would give us total control over the HTML - but would make the HTML messy.

A much cleaner approach that you can alternatively use is to take advantage of the "Html" helper property on the ViewPage base class.  This is a convenient object that exposes a set of HTML Helper UI methods that automate HTML UI generation.  For example, earlier in this post we used the Html.ActionLink helper method to generate <a href=""> elements:

The HtmlHelper object (as well as the AjaxHelper object - which we'll talk about in a later tutorial) have been specifically designed to be easily extended using "Extension Methods" - which is a new language feature of VB and C# in the VS 2008 release.  What this means is that anyone can create their own custom helper methods for these objects and share them for you to use. 

We'll have dozens of built-in HTML and AJAX helper methods in future previews of the ASP.NET MVC Framework.  In the first preview release only the "ActionLink" method is built-into System.Web.Extensions (the assembly where the core ASP.NET MVC framework is currently implemented).  We do, though, also have a separate "MVCToolkit" download that you can add to your project to obtain dozens more helper methods that you can use with the first preview release. 

To install the MVCToolkit HTML Helper methods, simply add the MVCToolkit.dll assembly to your project references:

Re-build your project.  And then the next time you type <%= Html. %> you'll see many, many more additional UI helpers that you can use:

To build our HTML <select> dropdowns we could use the Html.Select() method.  Each method comes with overloaded method versions - all with full intellisense inside our views:

We could update our "New" view to use the Html.Select options to display dropdownlists that use the CategoryID/SupplierID properties as the values and CategoryName/SupplierName as the display text using the code below:

This will generate the appropriate <select> HTML markup for us at runtime:

And give end-users an easier way to pick the Product Category and Supplier on our /Products/New screen:

Note: because we are still posting a CategoryID and SupplierID value to the server, we do not need to update our ProductsController Create Action at all to support this new drop-downlist UI - it will just work.

Implementing Add New Product (Part 4 - Cleaning Up Create with the UpdateFrom Method)

Our ProductsController's "Create" Action method is responsible for handling the form posting of our "Add Product" scenario.   It currently handles incoming form parameters as arguments to the action method:

This approach works fine - although for forms involving large amounts of values the method signatures on Actions can start to become a little hard to read.  The code above that sets all of the incoming parameter values to the new Product object is also a little long and monotonous.

If you reference the MVCToolkit assembly, you can optionally take advantage of a useful Extension Method implemented within the System.Web.Mvc.BindingHelpers namespace that can help clean this up a little.  It is called "UpdateFrom" and can be used on any .NET object.  It takes a dictionary of values as an argument, and it will then automatically perform a property assignment on itself for any key that matches a public property on the object.

For example, we could re-write our Create action method above to use the UpdateFrom method like so:

 

Note: if you want to be more explicit for security reasons and only allow certain properties to be updated, you can also optionally pass a string array of the property names to update to the UpdateFrom method:

Implement Edit Product Functionality (Part 1 - Background)

Let's now implement the "Edit Product" functionality of our site.  We'll ultimately want users to see a screen like below when they visit the /Products/Edit/[ProductID] URL:

Like the "Add New Product" form post example above, we are going to implement this form edit interaction using two ProductsController Actions that we'll call "Edit" and "Update": 

"Edit" will display the product form.  "Update" will be used to handle the form's submit action.

Implement Edit Product Functionality (Part 2 - Edit Action)

We'll begin enabling our application's Edit functionality by implementing the ProductController's Edit action method.  When we created our product listing page at the beginning of this post, we built it so that the Edit action will take an id argument as part of the URL (for example: /Products/Edit/5):

We'll want the Edit action method to retrieve the appropriate Product object from the database, as well as retrieve collections of the available Suppliers and Categories (so that we can implement dropdowns in our edit view).  We'll define a strongly typed view object to represent all of this using the ProductsEditViewData object below:

We can then implement our Edit action method to populate this viewdata object and Render it with an "Edit" view:

Implement Edit Product Functionality (Part 2 - Edit View)

We can implement the "Edit.aspx" view page using the following approach:

Note how we are using both the Html.TextBox and Html.Select helper methods in the sample above.  Both of these are extension methods from the MVCToolkit.dll assembly.

Notice how the Html.Select helper method has an overloaded version that allows you to specify what the selected value is in the dropdownlist.  In the snippet below I'm indicating that I want the Category drop down item to be automatically selected based on the edit product's current CategoryID value:

Lastly - notice how we are using the Url.Action() helper method to set the <form> element's "action" attribute:

Both the Url.Action and Html.ActionLink helper methods use the ASP.NET MVC Framework's Routing Engine to generate URLs (read Part 2 for details on how URL generation works).  What this means is that if we change the routing rules for Edits in our site, we will not need to change any of the code in our Controller or View.  For example, we could re-map our URLs to use a more RESTful URL like /Products/1/Edit instead of /Products/Edit/1, and have the above Controller and View continue to work unmodified. 

Implement Edit Product Functionality (Part 3 - Update Action)

Our last step will be to implement the "Update" action method on our ProductController class: 

Like our previous "Create" action method we'll take advantage of the "UpdateFrom" extension method to automatically populate our product object from the request.  Notice that rather then populate an empty product object though, we are using a pattern where we first retrieve the old values from the database, then apply the changes the user made to them, and then save them in the database. 

Once the edit is made, we redirect back to the Product Listing page - and automatically set the /Products/Category/[CategoryID] to match the saved state of the Product we were working on.

Summary

Hopefully this post has helped provide some more details about how to handle Form Input and Post scenarios with the ASP.NET MVC Framework, as well as provided some context for how you can handle and structure common data entry and edit scenarios with it.

Click here to download a .ZIP file that contains the source code for the completed application we built above.

In future posts I'll cover how to handle validation and error recovery situations with form input and editing scenarios. I'll talk about some of the data and security scaffolding support built-in to enable rapid application creation.  I'll discuss how you can use ASP.NET AJAX to perform AJAX-enabled edits using the MVC framework.  And I'll drill deeper into how you can unit test and add dependency injection to your Controllers.

Hope this helps,

Scott

December 8th Links: ASP.NET, ASP.NET AJAX, ASP.NET MVC, .NET, VS 2008

Here is the latest in my link-listing series.  Also check out my ASP.NET Tips, Tricks and Tutorials page for links to popular articles I've done myself in the past.

Several people have pinged me asking for the download location of the ASP.NET 3.5 Extensions Preview.  We were hoping to post it on the web Friday, but unfortunately found a late bug that we felt needed to be fixed.  The team is working this weekend to sign off on the new build.  We hope to be able to post it as soon as this is done - apologies for the delay.

ASP.NET

  • Taking an ASP.NET Application Offline: Scott Mitchell has a good article on 4GuysFromRolla that discusses a few approaches you can use to temporarily take down ASP.NET applications for updates/maintenance. 

ASP.NET AJAX

  • Sys.Debug in ASP.NET AJAX Framework: Roman Nikitin has a nice post that describes how to use the Sys.Debug feature of ASP.NET AJAX to easily instrument, debug and trace your AJAX applications. 

ASP.NET MVC

  • TDD and Dependency Injection with ASP.NET MVC: Phil Haack from the ASP.NET team writes about how to use TDD (test driven development) with the new ASP.NET MVC Framework.  He uses StructureMap and RhinoMocks to enable the Dependency Injection and Mocking support.

.NET

  • Hidden Gems in Visual Basic 2008: Amanda Silver from the VB team has an awesome post that discusses some of the new hidden gems with Visual Basic in VS 2008.  I actually learned a few of them for the first time reading her article!  Highly recommended reading.

  • LINQ to Active Directory is Here: Bart De Smet from my team has been working on a cool LINQ to Active Directory provider (previously called LINQ to LDAP) in his spare time.  You can learn how to use it in his series here, as well as read about how he built it (and learn a lot about how to build LINQ providers).

Visual Studio

Hope this helps,

Scott

ASP.NET MVC Framework (Part 3): Passing ViewData from Controllers to Views

The last few weeks I have been working on a series of blog posts that cover the new ASP.NET MVC Framework we are working on.  The ASP.NET MVC Framework is an optional approach you can use to structure your ASP.NET web applications to have a clear separation of concerns, and make it easier to unit test your code and support a TDD workflow.

The first post in this series built a simple e-commerce product listing/browsing site.  It covered the high-level concepts behind MVC, and demonstrated how to create a new ASP.NET MVC project from scratch to implement and test this e-commerce product listing functionality.  The second post in this series drilled deep into the URL routing architecture of the ASP.NET MVC framework, and discussed both how it worked as well as how you can handle more advanced URL routing scenarios with it.

In today's blog post I'm going to discuss how Controllers interact with Views, and specifically cover ways you can pass data from a Controller to a View in order to render a response back to a client.

Quick Recap from Part 1

In Part 1 of this series, we created an e-commerce site that implemented basic product listing/browsing support.  We implemented this site using the ASP.NET MVC Framework, which led us to naturally structure the code into distinct controller, model and view components.

When a browser sends a HTTP request to our web site, the ASP.NET MVC Framework will use its URL routing engine to map the incoming request to an action method on a controller class to process it.  Controllers in a MVC based application are responsible for processing incoming requests, handling user input and interactions, and executing application logic based on them (retrieving and updating model data stored in a database, etc).

When it comes time to render an HTML response back to the client, controllers typically work with "view" components - which are implemented as separate classes/templates from the controllers, and are intended to be focused entirely on encapsulating presentation logic. 

Views should not contain any application logic or database retrieval code, instead all application/data logic should only be handled by the controller class.  The motivation behind this partitioning is to help enforce a clear separation of your application/data logic from your UI generation code.  This makes it easier to unit test your application/data logic in isolation from your UI rendering logic.

Views should only render their output using the view-specific data passed to it by the Controller class.  In the ASP.NET MVC Framework we call this view-specific data "ViewData".  The rest of this blog post is going to cover some of the different approaches you can use to pass this "ViewData" from the Controller to the View to render.

A Simple Product Listing Scenario

To help illustrate some of the techniques we can use to pass ViewData from a Controller to a View, let's build a simple product listing page:

We will use a CategoryID integer to filter the products that we want to display for the page.  Notice above how we are embedding the CategoryID as part of the URL (for example: /Products/Category/2 or /Products/Category/4).

Our product listing page is then rendering two separate dynamic content elements. The first is the textual name of the category we are displaying (for example: "Condiments").  The second is an HTML <ul><li/></ul> list of product names.  I've circled both of these in red in the above screen-shot.

Below we'll look at two different approaches we can use to implement a "ProductsController" class that processes the incoming request, retrieves the data necessary to handle it, and then passes this data to a "List" view to render it.  The first approach we'll examine passes the data using a late-bound dictionary object.  The second approach we'll examine passes it using a strongly-typed class.

Approach 1: Passing ViewData using the Controller.ViewData Dictionary

The Controller base class has a "ViewData" dictionary property that can be used to populate data that you want to pass to a View.  You add objects into the ViewData dictionary using a key/value pattern.

Below is a ProductsController class with a "Category" action method that implements our product listing scenario above.  Notice how it is using the category's ID parameter to lookup the textual name of the category, as well as retrieve a list of the Products within that category.  It is storing both of these in the Controller.ViewData collection using a "CategoryName" and "Products" key:

 

Our Category action above is then calling RenderView("List") to indicate which view template it wants to render.  When you call RenderView like this it will pass the ViewData dictionary to the View in order for it to render.

Implementing Our View

We will implement our List view using a List.aspx file that lives under the \Views\Products directory of our project.  This List.aspx page will inherit the layout of the Site.Master MasterPage under the \Views\Shared folder (right click within VS 2008 and select Add New Item->MVC View Content Page to wire up a master page when you create a new view page):

When we create our List.aspx page using the MVC View Content Page template it derives not from the usual System.Web.UI.Page class, but rather from the System.Web.Mvc.ViewPage base class (which is a subclass of the existing Page class):

The ViewPage base class provides us with a ViewData dictionary property that we can use within the view page to access the data objects that were added by the Controller.  We can then take these data objects and use them to render HTML output using either server controls, or by using <%= %> rendering code.

Implementing Our View Using Server Controls

Below is an example of how we could use the existing <asp:literal> and <asp:repeater> server controls to implement our HTML UI:

We can bind the ViewData to these controls using the below code-behind class (note how we are using the ViewPage's ViewData dictionary to-do this):

Note: Because we have no <form runat="server"> on the page, no view-state is ever emitted.  The above controls also don't automatically render any ID value - which means that you have total control over the HTML emitted.

Implementing our View using <%= %> Code

If you prefer to use inline rendering code to generate the output, you can accomplish the same result as above using the List.aspx below:

Note: Because ViewData is typed as a dictionary containing "objects", we need to cast ViewData["Products"] to a List<Product> or an IEnumerable<Product> in order to use the foreach statement on it.  I am importing both the System.Collections.Generic and MyStore.Models namespaces on the page to avoid having to fully qualify the List<T> and Product types.

Note: The use of the "var" keyword above is an example of using the new C# and VB "type inference" feature in VS 2008 (read here for my previous post on this).  Because we have cast ViewData["Products"] as a List<Product> we get full intellisense on the product variable within the List.aspx file:

Approach 2: Passing ViewData using Strongly Typed Classes

In addition to supporting a late-bound dictionary approach, the ASP.NET MVC Framework also enables you to pass strongly typed ViewData objects from your Controller to your View.  There are a couple of benefits of using this strongly typed approach:

  1. You avoid using strings to lookup objects, and get compile-time checking of both your Controller and View code
  2. You avoid the need to explicitly cast values from the ViewData object dictionary when using strongly-typed languages like C#
  3. You get automatic code intellisense against your ViewData object within both the markup and code-behind of your view page
  4. You can use code refactoring tools to help automate changes across your app and unit-test code base

Below is a strongly typed "ProductsListViewData" class that encapsulates the data needed for the List.aspx view to render our product listing.  It has CategoryName and Products properties (implemented using the new C# automatic properties support):

We can then update our ProductsController implementation to use this object to pass a strongly typed ViewData object to our view:

Notice above how we are passing our strongly typed ProductsListViewData object to the View by adding it as an extra parameter to the RenderView() method.

Using the View's ViewData Dictionary with a Strongly Typed ViewData Object

The previous List.aspx view implementations we wrote will continue to work with our updated ProductsController - no code changes required.  This is because when a strongly typed ViewData object is passed to a View that derives from ViewPage, the ViewData dictionary will automatically use reflection against the properties of the strongly typed object to lookup values.  So code in our view like below:

will automatically use reflection to retrieve the value from the CategoryName property of the strongly typed ProductsListViewData object we passed when calling the RenderView method.

Using the ViewPage<T> Base Class to Strongly Type ViewData

In addition to supporting a dictionary based ViewPage base class, the ASP.NET MVC Framework also ships with a generics based ViewPage<T> implementation.  If your View derives from ViewPage<T> - where T indicates the type of the ViewData class the Controller passes to the view - then the ViewData property will be strongly typed using this class type.

For example, we could update our List.aspx.cs code-behind class to derive not from ViewPage, but from ViewPage<ProductsListViewData>:

When we do this, the ViewData property on the page will change from being a dictionary to being of type ProductsListViewData.  This means that instead of using string-based dictionary lookups to retrieve data, we can now use strongly typed properties:

We can then use either a sever-control approach, or a <%= %> rendering approach to render HTML based on this ViewData.

Implementing Our ViewPage<T> Implementation Using Server Controls

Below is an example of how we could use the <asp:literal> and <asp:repeater> server controls to implement our HTML UI.  This is the exact same markup that we used when our List.aspx page derived from ViewPage:

Below is what the code-behind now looks like.  Note how because we are deriving from ViewPage<ProductsListViewData> we can access the properties directly - and we don't need to cast anything (we'll also get refactoring tool support anytime we decide to rename one of the properties):

Implementing our ViewPage<T> implementation using <%= %> Code

If you prefer to use inline rendering code to generate the output, you can accomplish the same result as above using the List.aspx below:

Using the ViewPage<T> approach we now no longer need to use string lookups of the ViewData.  Even more importantly, notice above how we no longer need to cast any of the properties - since they are strongly typed.  This means we can write foreach (var product in ViewData.Products) and not have to cast Products.  We also get full intellisense on the product variable within the loop:

Summary

Hopefully the above post helps provide some more details about how Controllers pass data to a View in order to render a response to a client.  You can use either a late-bound dictionary, or a strongly-typed approach to accomplish this.

The first time you try and build an MVC application you will likely find the concept of splitting up and separating your application controller logic from your UI generation code a little strange.  It will probably take some dedicated app-building time before you become comfortable and orient your mind-set around the idea of processing a request, executing all of the application logic for it, packaging up the viewdata required to build a UI response, and then handing it off to a separate view page to render it.  Important: If this model doesn't feel comfortable to you then don't use it - the MVC approach is purely optional, and we don't think it is something everyone will want to use. 

The benefit and goal behind this application partitioning, though, is that it enables you to run and test your application and data logic in isolation from your UI rendering code.  This makes it much easier to develop comprehensive unit tests for your application, as well as to use a TDD (test driven development) workflow as you build your applications.  In later blog posts I'll drill in deeper into this more, as well as discuss best practices you can use to easily test your code.

Hope this helps,

Scott