Return View()
End Function
< NonAction() >
Sub NotAnAction()
' This method is not exposed as an action.
End Sub
End Class
The comment that appears above the Index method is a convention that
indicates how the action is triggered. Each action method is placed at a URL
that is a combination of the controller name and the action method name
formatted like /controller/action. The comment has no control over this
convention but is used to indicate where you can expect to fi nd this action
method. In this case it is saying that the index action is triggered by executing an
HTTP GET request against the URL /Products/. This is just the name of the
controller because an action named Index is assumed if one is not explicitly
stated by the URL. This convention is revisited in the section on routing.
The result of the Index method is an object that derives from the System.Web.Mvc.ActionResult
abstract class. This object is responsible for determining what happens after the action method
returns. A number of standard classes inherit from ActionResult that allow you to perform a
number of standard tasks, including redirection to another URL, generating some simple content in
a number of different formats, or in this case, rendering a view.
The View method on the Controller base class is a simple method that creates and
confi gures a System.Web.Mvc.ViewResult object. This object is responsible for
selecting a view and passing it any information that it needs to render its contents.
rendering a Ui with Views .
443
It is important to note that Index is just a normal .NET method and ProductsController is
just a normal .NET class. There is nothing special about either of them. This means that you can
easily instantiate a ProductsController in a test harness, call its Index method, and then make
assertions about the ActionResult object it returns.
Before moving on, update the Index method to retrieve a list of Products and pass them onto the
view, as shown in the following code listing:
c#
public ActionResult Index()
{
List<Product> products;
using (var db = new ProductsDataContext())
{
products = db.Products.ToList();
}
return View(products);
}
Code snippet Controllers\ProductsController.cs
Vb
Function Index() As ActionResult
Dim products As New List(Of Product)
Using db As New ProductsDataContext
products = db.Products.ToList()
End Using
Return View(products)
End Function
Code snippet Controllers\ProductsController.vb
Now that you have created a model and a controller all that is needed is to create the view to display
the UI.
renderinG a ui with Views
In the previous section you created an action method that gathers the complete list of products and
then passes that list to a view. Each view belongs to a single controller and is stored in a subfolder
in the Views folder, which is named after the controller that owns it. Additionally, there is a Shared
folder, which contains a number of shared views that are accessible from a number of controllers.
When the view engine is looking for a view it checks the controller-specific area first and then
checks in the shared area.
444 . chaPter 21 ASp.neT mVc
Each view looks very similar to a standard ASP.NET Web Forms Page or Control having either an
.aspx or .ascx extension. They contain a mix of HTML markup and code blocks. They can even
have master pages and render some standard controls. However, a number of important differences
exist that need to be highlighted.
First, a view doesn ’ t have a code - behind page. As such, there is nowhere to add event handlers for
any controls that the view renders, including those that normally happen behind the scenes. Instead,
it is expected that a controller will respond to user events and that the view will expose ways for
the user to trigger action methods. Second, instead of inheriting from System.Web.Page , a view
inherits from System.Web.Mvc.ViewPage . This base class exposes a number of useful properties
and methods that can be used to help render the
HTML output. One of these properties contains
a dictionary of objects that were passed into the
view from the controller. Finally, in the markup
you will notice that there is no form control with a
runat= ” server ” attribute. No server form means
that there is no View State emitted with the page.
The majority of the ASP.NET server controls must
be placed inside a server form. Some controls such
a Literal or Repeater control will work fi ne outside
a form; however, if you try to use a Button or
DropDownList control, your page will throw an
exception at run time.
You can create a View in a number of ways, but the
easiest is to right - click the title of the action method
and select Add View, which brings up the Add View
dialog shown in Figure 21 - 5. fiGure 21 - 5
You can specify the full path to a view as the view name if you need to refer to a
view that is not in the normal view engine search areas.
You can use the shortcut Ctrl+M, Ctrl+V when the cursor is inside an action
method to open the Add View dialog as well.
This dialog contains a number of options. By default, the name is set to match the name of the
action method. If you change this, you need to change the call to View to include the view name as
a parameter. Check the box to create a strongly typed view and then choose Models.Product from
the View Data Class drop - down. If you don ’ t see the Product class straight away you might need to
build the application before adding the view.
rendering a Ui with Views .
445
If you do not opt to create a strongly typed view, it will contain a dictionary of
objects that will need to be converted back into their real types before you can
use them. It is recommended to always use strongly typed views. If you require
your views to be weakly typed and you are using C#, you should create a strongly
typed view of the new dynamic type and pass it ExpandoObject instances.
Finally, change the View Content drop-down to List. This tells Visual Studio to generate a list page
for Product objects. When you click Add, the view should be generated and opened in the main
editor window. It will look like this:
c#
< %@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage < IEnumerable < CSProductsMVC.Models.Product > > " % >
< asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server" >
Index
</asp:Content>
<asp:Content ID=”Content2” ContentPlaceHolderID=”MainContent” runat=”server”>
<h2>Index</h2>
<table>
<tr>
<th></th>
<th>ProductID</th>
<th>Name</th>
<th>ProductNumber</th>
<th>MakeFlag</th>
<th>FinishedGoodsFlag</th>
<th>Color</th>
<th>SafetyStockLevel</th>
<th>ReorderPoint</th>
<th>StandardCost</th>
<th>ListPrice</th>
<th>Size</th>
<th>SizeUnitMeasureCode</th>
<th>WeightUnitMeasureCode</th>
<th>Weight</th>
<th>DaysToManufacture</th>
<th>ProductLine</th>
<th>Class</th>
<th>Style</th>
<th>ProductSubcategoryID</th>
<th>ProductModelID</th>
<th>SellStartDate</th>
<th>SellEndDate</th>
<th>DiscontinuedDate</th>
446 .
chaPter 21 ASp.neT mVc
<th>rowguid</th>
<th>ModifiedDate</th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td>
<%= Html.ActionLink(“Edit”, “Edit”, new { id=item.ProductID }) %> |
<%= Html.ActionLink(“Details”, “Details”, new
{ id=item.ProductID })%>
</td>
<td><%= Html.Encode(item.ProductID) %></td>
<td><%= Html.Encode(item.Name) %></td>
<td><%= Html.Encode(item.ProductNumber) %></td>
<td><%= Html.Encode(item.MakeFlag) %></td>
<td><%= Html.Encode(item.FinishedGoodsFlag) %></td>
<td><%= Html.Encode(item.Color) %></td>
<td><%= Html.Encode(item.SafetyStockLevel) %></td>
<td><%= Html.Encode(item.ReorderPoint) %></td>
<td><%= Html.Encode(String.Format(“{0:F}”, item.StandardCost)) %></td>
<td><%= Html.Encode(String.Format(“{0:F}”, item.ListPrice)) %></td>
<td><%= Html.Encode(item.Size) %></td>
<td><%= Html.Encode(item.SizeUnitMeasureCode) %></td>
<td><%= Html.Encode(item.WeightUnitMeasureCode) %></td>
<td><%= Html.Encode(String.Format(“{0:F}”, item.Weight)) %></td>
<td><%= Html.Encode(item.DaysToManufacture) %></td>
<td><%= Html.Encode(item.ProductLine) %></td>
<td><%= Html.Encode(item.Class) %></td>
<td><%= Html.Encode(item.Style) %></td>
<td><%= Html.Encode(item.ProductSubcategoryID) %></td>
<td><%= Html.Encode(item.ProductModelID) %></td>
<td><%= Html.Encode(String.Format(“{0:g}”, item.SellStartDate)) %></td>
<td><%= Html.Encode(String.Format(“{0:g}”, item.SellEndDate)) %></td>
<td><%= Html.Encode(String.Format(“{0:g}”,
item.DiscontinuedDate)) %></td>
<td><%= Html.Encode(item.rowguid) %></td>
<td><%= Html.Encode(String.Format(“{0:g}”, item.ModifiedDate)) %></td>
</tr>
<% } %>
</table>
<p>
<%= Html.ActionLink(“Create New”, “Create”) %>
</p>
</asp:Content>
Code snippet Views\Products\Index.aspx
rendering a Ui with Views .
447
Vb
<%@ Page Title=”” Language=”VB” MasterPageFile=”~/Views/Shared/Site.Master”
Inherits=”System.Web.Mvc.ViewPage(Of IEnumerable (Of ProductsMVC.Product))” %>
<asp:Content ID=”Content1” ContentPlaceHolderID=”TitleContent” runat=”server”>
Index
</asp:Content>
<asp:Content ID=”Content2” ContentPlaceHolderID=”MainContent” runat=”server”>
<h2>Index</h2>
<p>
<%=Html.ActionLink(“Create New”, “Create”)%>
</p>
<table>
<tr>
<th></th>
<th>ProductID</th>
<th>Name</th>
<th>ProductNumber</th>
<th>MakeFlag</th>
<th>FinishedGoodsFlag</th>
<th>Color</th>
<th>SafetyStockLevel</th>
<th>ReorderPoint</th>
<th>StandardCost</th>
<th>ListPrice</th>
<th>Size</th>
<th>SizeUnitMeasureCode</th>
<th>WeightUnitMeasureCode</th>
<th>Weight</th>
<th>DaysToManufacture</th>
<th>ProductLine</th>
<th>Class</th>
<th>Style</th>
<th>ProductSubcategoryID</th>
<th>ProductModelID</th>
<th>SellStartDate</th>
<th>SellEndDate</th>
<th>DiscontinuedDate</th>
<th>rowguid</th>
<th>ModifiedDate</th>
</tr>
<% For Each item In Model%>
<tr>
<td>
<%=Html.ActionLink(“Edit”, “Edit”, New With
{.id = item.ProductID})%> |
448 .
chaPter 21 ASp.neT mVc
<%=Html.ActionLink(“Details”, “Details”, New With
{.id = item.ProductID})%>
</td>
<td><%= Html.Encode(item.ProductID) %></td>
<td><%= Html.Encode(item.Name) %></td>
<td><%= Html.Encode(item.ProductNumber) %></td>
<td><%= Html.Encode(item.MakeFlag) %></td>
<td><%= Html.Encode(item.FinishedGoodsFlag) %></td>
<td><%= Html.Encode(item.Color) %></td>
<td><%= Html.Encode(item.SafetyStockLevel) %></td>
<td><%= Html.Encode(item.ReorderPoint) %></td>
<td><%= Html.Encode(String.Format(“{0:F}”, item.StandardCost)) %></td>
<td><%= Html.Encode(String.Format(“{0:F}”, item.ListPrice)) %></td>
<td><%= Html.Encode(item.Size) %></td>
<td><%= Html.Encode(item.SizeUnitMeasureCode) %></td>
<td><%= Html.Encode(item.WeightUnitMeasureCode) %></td>
<td><%= Html.Encode(String.Format(“{0:F}”, item.Weight)) %></td>
<td><%= Html.Encode(item.DaysToManufacture) %></td>
<td><%= Html.Encode(item.ProductLine) %></td>
<td><%= Html.Encode(item.Class) %></td>
<td><%= Html.Encode(item.Style) %></td>
<td><%= Html.Encode(item.ProductSubcategoryID) %></td>
<td><%= Html.Encode(item.ProductModelID) %></td>
<td><%= Html.Encode(String.Format(“{0:g}”, item.SellStartDate)) %></td>
<td><%= Html.Encode(String.Format(“{0:g}”, item.SellEndDate)) %></td>
<td><%= Html.Encode(String.Format(“{0:g}”,
item.DiscontinuedDate)) %></td>
<td><%= Html.Encode(item.rowguid) %></td>
<td><%= Html.Encode(String.Format(“{0:g}”, item.ModifiedDate)) %></td>
</tr>
<% Next%>
</table>
</asp:Content>
Code snippet Views\Products\Index.aspx
This view presents the list of Products in a simple table. The bulk of the work is done by a for each
loop, which iterates over the list of products and renders an HTML table row for each one.