Creating views is a very straightforward process. It has an action method called NotFound that is called if we have a request to display information about a pet that is not in the system. The view basically just needs to say that the pet has not been found. The action method is shown in Listing 1.
Listing 1. NotFound Action Method in the PetController Class
public ActionResult NotFound()
{
return View();
}
One of the easiest ways to create a view for an action method is to right-click anywhere inside the action method and select the option “Add View,” as shown in Figure 1.

Figure 1. Right-click anywhere inside the action method to create a view
Doing this opens the Add View dialog, shown in Figure 2. In the dialog, you can set the properties of the view, which I’ll describe in a moment.

Figure 2. Add View dialog
In the “View name” text box, enter the name of the view. Generally, you’ll want to give the view the same name as the action method that triggered it. Sometimes, though, you’ll want the view to have a different name from that of the action method. In this case, the action method must specify the name of the view as follows:
return View(name-of-view);
The “View engine” drop-down list of the Add View dialog enables you to choose which view engine your view will use to process server-side code. As described earlier in the blog, you can choose between the ASPX view engine and the more modern Razor view engine.
The following check boxes in the Add View dialog offer three additional view characteristics that you can specify:
• Create a strongly-typed view: Check this box if you want to make your view a strongly typed view, which is a view that receives a known type of “model” object as a parameter from the controller action method. Using strongly typed views has several advantages, such as:
=> IntelliSense: Visual Studio will be capable of displaying IntelliSense using the Model property based on the view model class. This allows the view page to access properties on the model object, call methods, and so forth.
=> Automatic scaffolding: Selecting this option instructs Visual Studio to create a view with a <form> tag that includes all the fields and validation options based on the properties defined in the view model class.
=> Compile-time type checking: The compiler is able to detect problems with data type handling in the view because it knows the view model class and its properties. For example, if the view page tries to access a property that doesn’t exist on the model object, you’ll get a compiler error rather than a runtime error. This is a good thing, because it helps you fix problems in your code more easily.
• Create as a partial view: Check this box to define the view as a partial view, which is a chunk of HTML that can be reused in other views. For example, a partial view can contain the logic to display a chart based on a set of data. This chart then can be placed in different views, but the logic remains centralized in a single partial view. This means that if you modify the chart type, for example, from a bar chart to a pie chart, all views having the same chart will be displayed as a pie chart.
• Use a layout or master page: Checking this box allows you to define a view that serves as a general layout with elements such as a logo, a top menu, and a footer that will be the same across all views that use it. This is a good way to give your web site a consistent look and feel. Also, changes that you make in this shared view apply to all views that use it, which is much easier than having to make the changes in each individual view. In Razor, there is a default layout view called _ViewStart.cshtml (or _ViewStart.vbhtml if your server-side language is VB.NET). The _ViewStart.cshtml view is used if you selected the check box “Use a layout or master page” and left the layout input box empty (as shown in Figure 2).
The last field in the Add View dialog is the ContentPlaceHolder ID, which you use when you choose ASPX as the view engine. It is the ID of the ContentPlaceHolder element in the master page that defines where the view content will be rendered to create a whole HTML document to be sent to the client browser. If you are using the Razor view engine, then this field is not available (as shown in Figure 5-2). Using the ASPX view engine is the old way, and I strongly suggest you use Razor instead. The best way to see how the ContentPlaceHolder ID setting works is with an example. Listing 2 includes a master page that defines a general layout for other views. Note that the HTML code includes two server-side elements, one in the <head> section and another in the <body> section. These elements are defined by <asp:ContentPlaceHolder>.
Listing 2. Sample Master Page That Uses the ASPX View Engine
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<!DOCTYPE html>
<html>
<head runat="server">
<meta name="viewport" content="width=device-width" />
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
</head>
<body>
<div>
<asp:ContentPlaceHolder ID="MainContent" runat="server">
</asp:ContentPlaceHolder>
</div>
</body>
</html>
The ContentPlaceHolder elements are meant to be replaced at runtime by HTML generated from the specific views that use the master page. For example, the view in Listing 5-8 has two <asp:Content> elements, each of which has a ContentPlaceHolderID property that refers to the ID of the ContentPlaceHolder elements in the master page.
Listing 3. View Implementing the Master Page from Listing2
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/ViewMasterPage1.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Index
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Index</h2>
</asp:Content>
At runtime, a call to the view will cause the HTML in the master page to be rendered as part of the HTML in the view, as shown in Listing 4; the areas where the view HTML was inserted in the master page appears in bold.
Listing 4. Resulting HTML Sent to the Browser Based on the Master Page and the View
<!DOCTYPE html>
<html>
<head><meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<h2>Index</h2>
</div>
</body>
</html>
The Rendering Process
Once you have created the view for the action method in Listing 1, all you need to do is compile the application so it can start accepting requests to render the view. Let’s see what happens when you create a view and name it, for example, not-found.cshtml instead of NotFound.cshtml, which is the expected view name for the NotFound() action method.
If you run the application and make a request to Pet/NotFound, the request will be handled by the NotFound action method in the PetController class. The NotFound() action method returns a ViewResult by calling return View(). Because a specific view was not requested, the framework will try to render a view named NotFound.cshtml and you will get a response like the one shown in Figure 3.

Figure 3. Error displayed when rendering a view that doesn’t exist or has a different name than the action method
Figure 3 displays a lot of information that is important to examine. First, notice that the framework looked for a view with the name NotFound in two different directories: Views/Pet and Views/Shared. The Pet directory inside the Views directory represents a place for all views created based on the PetController class; it is another convention of ASP.NET MVC, by default it will look for a folder with the name of the controller class for views that are to be rendered by action methods defined in the controller. The second directory, Views/Shared, is a directory for views that don’t have a direct relationship with an action method in a controller class but can be used by many action methods in different controllers (layout pages and partial views are good examples of shared views).
Second, notice in Figure 3 that the framework looks for files with different extensions, because each view engine uses different file extensions. The extensions .aspx and .ascx are used by the ASPX view engine, while the .cshtml and .vbhtml file extensions are used by the Razor view engine. In the world of the ASPX view engine, .aspx files are for views and .ascx files are for partial views. When you use the Razor view engine, you have only one file extension for your views: .cshtml is defined for views (and partial views) when your project uses the C# language, and .vbhtml is defined for views when your project uses VB.NET.
Third, the message states that one probable cause for the error is that it could not find the master page the view is using. This can happen if you renamed the master page or moved it to a different location. If the view was created following the conventions and has the content in Listing 5, you will see the result shown in Figure 4.
Listing 5. Content of the Views/Pet/NotFound.cshtml View
@{
ViewBag.Title = "NotFound";
}
<h1>The information you are looking could not be found</h1>

Figure 4. Result of the NotFound view rendered in the browser
Listing 1. NotFound Action Method in the PetController Class
public ActionResult NotFound()
{
return View();
}
One of the easiest ways to create a view for an action method is to right-click anywhere inside the action method and select the option “Add View,” as shown in Figure 1.
Figure 1. Right-click anywhere inside the action method to create a view
Doing this opens the Add View dialog, shown in Figure 2. In the dialog, you can set the properties of the view, which I’ll describe in a moment.
Figure 2. Add View dialog
In the “View name” text box, enter the name of the view. Generally, you’ll want to give the view the same name as the action method that triggered it. Sometimes, though, you’ll want the view to have a different name from that of the action method. In this case, the action method must specify the name of the view as follows:
return View(name-of-view);
The “View engine” drop-down list of the Add View dialog enables you to choose which view engine your view will use to process server-side code. As described earlier in the blog, you can choose between the ASPX view engine and the more modern Razor view engine.
The following check boxes in the Add View dialog offer three additional view characteristics that you can specify:
• Create a strongly-typed view: Check this box if you want to make your view a strongly typed view, which is a view that receives a known type of “model” object as a parameter from the controller action method. Using strongly typed views has several advantages, such as:
=> IntelliSense: Visual Studio will be capable of displaying IntelliSense using the Model property based on the view model class. This allows the view page to access properties on the model object, call methods, and so forth.
=> Automatic scaffolding: Selecting this option instructs Visual Studio to create a view with a <form> tag that includes all the fields and validation options based on the properties defined in the view model class.
=> Compile-time type checking: The compiler is able to detect problems with data type handling in the view because it knows the view model class and its properties. For example, if the view page tries to access a property that doesn’t exist on the model object, you’ll get a compiler error rather than a runtime error. This is a good thing, because it helps you fix problems in your code more easily.
• Create as a partial view: Check this box to define the view as a partial view, which is a chunk of HTML that can be reused in other views. For example, a partial view can contain the logic to display a chart based on a set of data. This chart then can be placed in different views, but the logic remains centralized in a single partial view. This means that if you modify the chart type, for example, from a bar chart to a pie chart, all views having the same chart will be displayed as a pie chart.
• Use a layout or master page: Checking this box allows you to define a view that serves as a general layout with elements such as a logo, a top menu, and a footer that will be the same across all views that use it. This is a good way to give your web site a consistent look and feel. Also, changes that you make in this shared view apply to all views that use it, which is much easier than having to make the changes in each individual view. In Razor, there is a default layout view called _ViewStart.cshtml (or _ViewStart.vbhtml if your server-side language is VB.NET). The _ViewStart.cshtml view is used if you selected the check box “Use a layout or master page” and left the layout input box empty (as shown in Figure 2).
The last field in the Add View dialog is the ContentPlaceHolder ID, which you use when you choose ASPX as the view engine. It is the ID of the ContentPlaceHolder element in the master page that defines where the view content will be rendered to create a whole HTML document to be sent to the client browser. If you are using the Razor view engine, then this field is not available (as shown in Figure 5-2). Using the ASPX view engine is the old way, and I strongly suggest you use Razor instead. The best way to see how the ContentPlaceHolder ID setting works is with an example. Listing 2 includes a master page that defines a general layout for other views. Note that the HTML code includes two server-side elements, one in the <head> section and another in the <body> section. These elements are defined by <asp:ContentPlaceHolder>.
Listing 2. Sample Master Page That Uses the ASPX View Engine
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<!DOCTYPE html>
<html>
<head runat="server">
<meta name="viewport" content="width=device-width" />
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
</head>
<body>
<div>
<asp:ContentPlaceHolder ID="MainContent" runat="server">
</asp:ContentPlaceHolder>
</div>
</body>
</html>
The ContentPlaceHolder elements are meant to be replaced at runtime by HTML generated from the specific views that use the master page. For example, the view in Listing 5-8 has two <asp:Content> elements, each of which has a ContentPlaceHolderID property that refers to the ID of the ContentPlaceHolder elements in the master page.
Listing 3. View Implementing the Master Page from Listing2
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/ViewMasterPage1.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Index
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Index</h2>
</asp:Content>
At runtime, a call to the view will cause the HTML in the master page to be rendered as part of the HTML in the view, as shown in Listing 4; the areas where the view HTML was inserted in the master page appears in bold.
Listing 4. Resulting HTML Sent to the Browser Based on the Master Page and the View
<!DOCTYPE html>
<html>
<head><meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<h2>Index</h2>
</div>
</body>
</html>
The Rendering Process
Once you have created the view for the action method in Listing 1, all you need to do is compile the application so it can start accepting requests to render the view. Let’s see what happens when you create a view and name it, for example, not-found.cshtml instead of NotFound.cshtml, which is the expected view name for the NotFound() action method.
If you run the application and make a request to Pet/NotFound, the request will be handled by the NotFound action method in the PetController class. The NotFound() action method returns a ViewResult by calling return View(). Because a specific view was not requested, the framework will try to render a view named NotFound.cshtml and you will get a response like the one shown in Figure 3.
Figure 3. Error displayed when rendering a view that doesn’t exist or has a different name than the action method
Figure 3 displays a lot of information that is important to examine. First, notice that the framework looked for a view with the name NotFound in two different directories: Views/Pet and Views/Shared. The Pet directory inside the Views directory represents a place for all views created based on the PetController class; it is another convention of ASP.NET MVC, by default it will look for a folder with the name of the controller class for views that are to be rendered by action methods defined in the controller. The second directory, Views/Shared, is a directory for views that don’t have a direct relationship with an action method in a controller class but can be used by many action methods in different controllers (layout pages and partial views are good examples of shared views).
Second, notice in Figure 3 that the framework looks for files with different extensions, because each view engine uses different file extensions. The extensions .aspx and .ascx are used by the ASPX view engine, while the .cshtml and .vbhtml file extensions are used by the Razor view engine. In the world of the ASPX view engine, .aspx files are for views and .ascx files are for partial views. When you use the Razor view engine, you have only one file extension for your views: .cshtml is defined for views (and partial views) when your project uses the C# language, and .vbhtml is defined for views when your project uses VB.NET.
Third, the message states that one probable cause for the error is that it could not find the master page the view is using. This can happen if you renamed the master page or moved it to a different location. If the view was created following the conventions and has the content in Listing 5, you will see the result shown in Figure 4.
Listing 5. Content of the Views/Pet/NotFound.cshtml View
@{
ViewBag.Title = "NotFound";
}
<h1>The information you are looking could not be found</h1>
Figure 4. Result of the NotFound view rendered in the browser
No comments:
Post a Comment