256 Microsoft Visual Studio 2010: A Beginner’s Guide TIP You can change your VS Web server’s port number. If you open your project’s property page by right-mouse clicking on the project in Solution Explorer and select Properties, then select the Web tab on the left, under Servers, you can specify a specific port or make other Web server choices. For ASP.NET MVC, the important part of the URL is /Home/About. Home is the name of the Controller, and ASP.NET MVC appends Controller to the URL name, looking for the HomeController class, shown in Listing 9-1, physically located in the Controller folder, which is why it’s important to ensure you create files in the proper locations. About is an action, which corresponds to the About method shown in Listing 9-1. Similar to the About method, the Index action is run through the following URL: http://localhost:1042/Home/Index In a later section of this chapter, you’ll learn how ASP.NET MVC performs routing, which maps URLs to Controllers. Both the Index and About actions in Listing 9-1 invoke a method named View. This is a convention for invoking a View with the same name as the action method. For example, calling View in the Index action will show a View named Index, and the call to View in the About method will show a View named About. One more item to point out is how the Index action assigns a string to a collection called ViewData. The ViewData collection is one way for a Controller to pass Model data to a View. I’ll cover more on Controllers, including how to create your own, in a later part of this chapter, but now, let’s do a quick review of Views so that you can see what happens when they are invoked by the Controller. Displaying Views A View is what displays in the browser and allows interaction with the user. The View can display any information that a Controller passes to it. For example, notice that the Index action in Listing 9-1 assigns a string “Welcome to ASP.NET MVC!” with the “Message” key in the ViewData collection. Looking Inside a View Figure 9-3 shows the View in the browser, displaying the message. Listing 9-2 shows the Hypertext Markup Language (HTML) of the View displaying the message. The View actually has a combination of HTML and ASP.NET markup, sometimes referred to as ASPX, but I’ll refer to it as just HTML for the rest of the chapter. Chapter 9: Creating Web Applications with ASP.NET MVC 257 Listing 9-2 A View’s HTML <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> <asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server"> Home Page </asp:Content> <asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server"> <h2><%= Html.Encode(ViewData["Message"]) %></h2> <p> To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website"> http://asp.net/mvc </a>. </p> </asp:Content> A quick overview of Listing 9-2 shows that there is a Page directive with a couple of Content containers. The Page directive specifies a MasterPage and Inherits attributes. A MasterPage is a separate file that holds common HTML that can be shown on all pages of a site. You’ll see how the MasterPage works soon, but let’s stay focused on the current file in Listing 9-2 until then. ASP.NET MVC will compile this HTML into code behind the scenes, and the generated code will derive from the class defined by the Inherits attribute. The first Content container can hold metadata that goes into an HTML header . The second Content container has the information that will display on the screen. Notice the Html.Encode(ViewData["Message"]) inside of binding tags <%= and %>. Any time you add code or need to access ViewData that was passed by the Controller, you will use the binding tags. Encode is one of several helper methods of the Html class, more of which you’ll see soon. The purpose of Encode is to translate HTML tags into their encoded representations for security purposes, ensuring that you don’t show any harmful JavaScript, or other markup that could possibly execute, to the user. ViewData["Message"] should be familiar, as it was set in the Index action in Listing 9-2 but is now being read and displayed on the screen by this View. 258 Microsoft Visual Studio 2010: A Beginner’s Guide Organizing View Files The file structure in Figure 9-2 shows that Views appear in the Views folder and have a *.aspx file extension. Each subfolder under the Views folder corresponds to a Controller, and the Views within the subfolder correspond generally to Controller actions. When a Controller passes control to a View, by calling View, ASP.NET MVC searches for the View in the Views folder with the subfolder named the same as the Controller and the file named the same as the action calling the View. Notice that there is a Shared folder. Sometimes, you’ll want to have a View that is shared by two or more Controller actions, and you can put these shared V iews in the Shared subfolder. Whenever ASP.NET MVC doesn’t find a View in the Controller-named subfolder, it will search for the View in the Shared folder. An important file in the Shared subfolder is the MasterPage, which is discussed next. Assigning MasterPage Files Most sites on the Web have multiple pages, each with common elements. They all have the same header, menu, sidebars, and footers. When you first build a site, you can duplicate this common content with no trouble, but this copy-and-paste type duplication will cause a lot of headaches in the future. The first time you have to change the common elements, you’ll need to visit every page. If the site has only a few pages, no problem, but the reality is that most sites of any success grow to dozens or hundreds of pages. It is beyond practical to try to update every page on a site every time the common content changes. This is where MasterPages help, allowing you to specify the common content in one place where you can have content pages that use the MasterPage. Whenever something changes in the common content, you update the MasterPage, and every page of a site that uses the MasterPage is automatically updated. Listing 9-3 shows the MasterPage, created by ASP.NET MVC, that the content page in Listing 9-2 uses. Listing 9-3 A MasterPage <%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> Chapter 9: Creating Web Applications with ASP.NET MVC 259 <title> <asp:ContentPlaceHolder ID="TitleContent" runat="server" /> </title> <link href=" / /Content/Site.css" rel="stylesheet" type="text/css" /> </head> <body> <div class="page"> <div id="header"> <div id="title"> <h1>My MVC Application</h1> </div> <div id="logindisplay"> <% Html.RenderPartial("LogOnUserControl"); %> </div> <div id="menucontainer"> <ul id="menu"> <li> <%= Html.ActionLink("Home", "Index", "Home")%> </li> <li> <%= Html.ActionLink("About", "About", "Home")%> </li> </ul> </div> </div> <div id="main"> <asp:ContentPlaceHolder ID="MainContent" runat="server" /> <div id="footer"> </div> </div> </div> </body> </html> 260 Microsoft Visual Studio 2010: A Beginner’s Guide Moving from the top of Listing 9-3 down, you can see the MasterPage directive at the top of the page, which states that this is a MasterPage and ASP.NET MVC will handle the page appropriately. The DTD is a tag that specifies what Web standards this page supports, which is read by browsers to help them determine the best way to display the page. The rest of the page is framed inside of HTML tags and ASP.NET MVC markup. The html tag states that this is an HTML document. HTML documents have two parts, a head and a body, where the head is for metadata describing the page and the body contains display content. In HTML, a div tag blocks off a chunk of HTML and is useful for layout and organization of the page. The Hx tags, where x is a number between 1 and 6, describe headers, where h1 is the largest and h6 is the smallest. The ContentPlaceHolder controls are instrumental to the success of the MasterPage. If you look at the Content tags in Listing 9-2, you’ll see that they have a ContentPlaceHolderID that matches the ID attributes of the ContentPlaceHolder controls in Listing 9-3. What this means is that when the View renders, the MasterPage will display and ASP.NET MVC will inject the Content regions of the content pages into the matching ContentPlaceHolders of the MasterPage. ASP.NET MVC knows which MasterPage to use because the Page directive, as shown in Listing 9-2, specifies the MasterPage attribute. If you recall from the last section, Listing 9-2 had a binding expression for the Html Encode helper method. The MasterPage in Listing 9-3 introduces a couple more Html helper methods, RenderPartial and ActionLink. The ActionLink method has three parameters: id, controller, and action. When the ActionLink renders in the browser, it will transform into an anchor tag, a, with an id specified in the first parameter of ActionLink. When the user clicks the link in the browser, the application will navigate to the Controller in the third parameter of ActionLink and invoke the action in the second parameter of ActionLink. So, if the user clicked the link produced by ActionLink("About", "About", "Home"), ASP.NET MVC will invoke the About action of the Home Controller. The next section discusses RenderPartial in more detail. Partial Views (a.k.a. User Controls) It’s often the case that you’ve written View content on one page and need the same identical content on two or more pages. As explained with MasterPages, you want to avoid the maintenance work that comes with updating all of the content that is the same on multiple pages. While MasterPages are good for content that decorates pages across an entire site, a Partial View is ideal for limited reuse of View content on different pages of a site. Chapter 9: Creating Web Applications with ASP.NET MVC 261 A good example of where a Partial View is useful is illustrated in the code produced by the ASP.NET MVC Project Wizard, where it created the LogonUserControl.ascx. The terms Partial View and User Control are synonymous, where the term User Control is familiar to developers who have worked with previous versions of ASP .NET Web Forms. Partial View is consistent with the ASP.NET MVC perspective of Views, where a Partial View is not an entire View, but a chunk of View content that can be reused with multiple Views. It isn’t coincidence that this control is physically located in the Views Shared folder, considering that it can be used on multiple pages. Remember, if ASP.NET MVC can’t find a file in a View folder named after a Controller, it will look in the Shared folder. Listing 9-4 shows the contents of LogonUserControl.ascx. Listing 9-4 Contents of a Partial View <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> <% if (Request.IsAuthenticated) { %> Welcome <b><%= Html.Encode(Page.User.Identity.Name) %></b>! [ <%= Html.ActionLink("Log Off", "LogOff", "Account") %> ] <% } else { %> [ <%= Html.ActionLink("Log On", "LogOn", "Account") %> ] <% } %> The Control directive at the top of Listing 9-4 indicates that this is a Partial View. Within the control, you can see an if statement, where the language syntax is surrounded by <% and %> binding symbols. The additional syntax to separate code from markup might take a little getting used to, but it is typical in an MVC application to control how markup is rendered. The IsAuthenticated property of the Request object tells whether the current user is logged in, and the logic ensures the appropriate message displays. The ActionLink Html helper methods generate action tags with a URL for actions on the Account Controller. We’ve barely touched on routing and how a URL matches controllers and actions, but the next section explains how routes work in greater depth. 262 Microsoft Visual Studio 2010: A Beginner’s Guide Managing Routing ASP.NET MVC has a routing system that matches URLs to controllers with actions and the parameters passed to those actions. When you start a new ASP.NET MVC project, default routing will be established via a file called Global.asax, which is where many events affecting the application are placed. When you run an ASP.NET MVC application, it will use URLs of the form http://domain/controller/action/param1/param2/…/paramN? optionalArg=optionalVal. Here’s an example: http://localhost:1042/Home/About In this example, localhost:1042 is the domain, Home is the Controller, and About is the action. When ASP.NET MVC sees this URL, it will instantiate the HomeController class and call the About method. The Global.asax file has an Application_Start event that is called the first time the application runs. This is where routing is set up so that it will be in place for all of the requests while the application is running. Listing 9-5 shows the default routing for an ASP .NET MVC project. Listing 9-5 Setting up routing C#: using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace MyShopCS { // Note: For instructions on enabling IIS6 or IIS7 classic mode, // visit http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { Chapter 9: Creating Web Applications with ASP.NET MVC 263 controller = "Home", action = "Index", id = "" } // Parameter defaults ); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } } } VB: ' Note: For instructions on enabling IIS6 or IIS7 classic mode, ' visit http://go.microsoft.com/?LinkId=9394802 Public Class MvcApplication Inherits System.Web.HttpApplication Shared Sub RegisterRoutes(ByVal routes As RouteCollection) routes.IgnoreRoute("{resource}.axd/{*pathInfo}") ' MapRoute takes the following parameters, in order: ' (1) Route name ' (2) URL with parameters ' (3) Parameter defaults routes.MapRoute( _ "Default", _ "{controller}/{action}/{id}", _ New With { .controller = "Home", .action = "Index", .id = "" } ) End Sub Sub Application_Start() AreaRegistration.RegisterAllAreas() RegisterRoutes(RouteTable.Routes) End Sub End Class 264 Microsoft Visual Studio 2010: A Beginner’s Guide Listing 9-5 shows that the Application_Start event invokes a method named RegisterRoutes, passing the Routes property of the RouteTable class. The Routes property is a static RouteCollection, meaning that there is only one copy for the entire application, and it will hold multiple routes. When the application starts, this collection will be empty and the RegisterRoutes method will populate the collection with routes for this application. Routing works by pattern matching, which you can see through the two statements in the RegisterRoutes method: IgnoreRoute and MapRoute. IgnoreRoute is useful for situations where you want to let IIS request the exact URL. In this case, it is any file with the *.axd extension, regardless of parameters. The MapRoute method shows a common pattern for matching URLs to controllers, actions, and parameters. The first parameter is the name of the route. The second parameter describes the pattern, where each pattern match is defined between curly braces. Based on the URL, http://localhost:1042/Home/About, the pattern, {controller}/{action}/ {id}, matches Home to {controller} and About to {action}; there is no match for {id}. Therefore, ASP.NET MVC will append “Controller” to the URL segment that matches {controller}, meaning that the Controller name to instantiate is HomeController. About is the method inside of HomeController to invoke. Since About doesn’t have parameters, supplying the {id} is unnecessary. The third parameter for MapRoute specifies default values, where the key matches the pattern parameter and the value assigned to the key is what ASP.NET MVC uses when it doesn’t find a pattern match with the URL. Here are a couple of examples: ● http://localhost:1042 invokes the Index method of HomeController because no Controller or action matches and the defaults are Home for {controller} and Index for {action}. ● http://localhost:1042/Home invokes the Index method of HomeController because no action was specified and the default value for {action} is Index. You can create your own custom route by using the MapRoute method and specifying other default values for the parameters. Building a Customer Management Application Now, we’ll pull together the ASP.NET MVC concepts you’ve learned and describe how to build a very simple application that displays, adds, modifies, and deletes customers. In so doing, you’ll see how to build up a Model that supports customers, how to create a custom Controller with actions for managing customers, and how to create multiple views to handle interaction with the users as they work with customers. . 256 Microsoft Visual Studio 2010: A Beginner’s Guide TIP You can change your VS Web server’s port number. If you open. Listing 9-2 but is now being read and displayed on the screen by this View. 258 Microsoft Visual Studio 2010: A Beginner’s Guide Organizing View Files The file structure in Figure 9-2 shows that. </div> </div> </div> </body> </html> 260 Microsoft Visual Studio 2010: A Beginner’s Guide Moving from the top of Listing 9-3 down, you can see the MasterPage