Using MVC Views. Objectives. Using MVC Views

Using MVC Views Using MVC Views Objectives  Learn about how views work in an MVC application.  Explore the various ways of adding dynamic conten...
Author: Rosalind Harris
6 downloads 1 Views 639KB Size
Using MVC Views

Using MVC Views Objectives 

Learn about how views work in an MVC application.



Explore the various ways of adding dynamic content to a view.

The files associated with this chapter are located in the following folders: ○ {Install Folder}\Views ○ {Install Folder}\ViewsLab ○

{Install Folder}\ViewsLabCompleted

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-1

Using MVC Views

Views in ASP.NET MVC The views in your ASP.NET MVC application are what a user sees. Views are the window into your application, and so is one of the most important parts of the application…along with all the rest of it! Views provide one of the biggest reasons to use MVC instead of Web forms. Unlike Web forms, you have complete control over the HTML that the application generates. There are no server controls as there are in Web forms that spew HTML, which you have little control over or that are hard to use with CSS and client-side JavaScript. Having complete control over HTML sounds great in theory, but it could also mean that you’d have to write a lot more HTML by hand. One of the big selling points of Web forms is that you can do drag and drop development, using server controls that generate massive amounts of HTML based on the properties you set and the data you bind to the controls. But MVC has a lot of features built in that make the job of writing HTML and other code simpler and more manageable, while letting you retain control over most of the generated HTML. And when you need complete control, you can bypass the MVC features and write all the beautiful HTML you care to write. The trick to writing good views in MVC is to keep the view focused on the user interface only. This means that there should be no code that directly reads or writes to a data store, no business rule implementations, nothing that isn’t directly related to interacting with the user. The ideal view should consist of a lot of HTML, maybe some client-side JavaScript (perhaps including Ajax), and a little code that reads data from the model or ViewData for the purpose of displaying data to the user. It might be appropriate to put some logic in a view, but it should only be presentation logic needed to dynamically interact with the user. Anything else you should rip out and put in the controller or model. Make that your solemn goal. The purest way to think about views is that the controller hands a model to the view, and the view converts it into something that is presented to the user. We’ve found this way of thinking to be a helpful context for understanding what views do and how to create them, as well as where to implement different kinds of logic. In this chapter, you’ll learn about how views work, how you can add dynamic data to the view, a little bit about the view engine that makes it all work, and ways to adhere to MVC’s DRY—Don’t Repeat Yourself—principle by creating reusable controls that you can use in multiple views.

4-2

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Views in ASP.NET MVC Figure 1 shows a graphic view of the interactions of the components of an MVC application. In order to handle a user request, the controller interacts with the model in whatever way is necessary to respond to the request. The controller then selects a view and passes it whatever data the view requires to generate a page. The view engine then reads the view template and dynamically generates the HTML that is sent to the user.

Figure 1. Anatomy of an MVC request and response.

In this chapter, you’ll learn some of the many features you can use to build views that provide a robust user interface for your applications. The MVC framework has a rich infrastructure for creating responsive and attractive Web sites for your users.

The Web Forms View Engine In the first two releases of MVC, the engine that processed the views you defined into HTML was, by default, the same engine used by ASP.NET Web forms. Appropriately enough, this engine is called the WebForms view engine. This engine is built on the WebFormViewEngine class, which provides many of the most useful ASP.NET features: master pages, server controls, some types of caching, design tools in Visual Studio, and lots more. As a result of sharing the view engine with Web forms, you could build MVC views that look an awful lot like Web form pages, with the same syntax for code nuggets that embed code, @Page directives, and even server controls if you care to use them (although you generally should not). But a view does not use many of the features implemented in the System.Web.UI.Page class—on which Web forms pages are built—including events, the Page lifecycle, ViewState, and other Web forms features. Instead, a view derives from System.Web.Mvc.ViewPage, which gives a view its features that are unique to an MVC application.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-3

Using MVC Views Interestingly, ViewPage inherits from Page, so if you really want or need to use some of the Web forms features implemented by Page you can do so. But those features aren’t likely to behave as you’d expect, and bridging the Web forms and MVC technologies is not likely to be a satisfying solution.

NOTE

Creating views can be a little confusing if you’re used to Web forms, but as long as you remember that there is no code-behind file or page events, you should be able to keep everything clear. Remember too that the only interaction with the rest of the application is through a controller, and all the controller really does is pass the view some data in the form of a model and other ViewData key/value pairs.

The Razor View Engine In MVC 3, Microsoft included a second view engine in the box, Razor, which uses what Scott Guthrie at Microsoft calls a code-focused templating approach. Guthrie, widely known as the father of ASP.NET, detailed several design goals for Razor: 

Compact, Expressive, and Fluid. A Razor view uses a simple @ character as a code nugget marker without the need for a closing character. It is intended to minimize the number of keystrokes you need to create a view. In most cases, Razor doesn’t require anything to mark the end of a code block because its parser is able to infer the end of the block.



Easy to Learn. Even though it is feature rich, Razor is easy to learn. A typical developer with extensive ASP.NET experience could probably learn enough in half a day to be immediately productive, and you can use your existing HTML and .NET programming language skills.



Not New. Razor doesn’t involve a new imperative language. Instead, it is a mix of HTML and your choice of either C# or VB, along with a few new syntactical details to learn.



Works with Any Text Editor. Visual Studio has its usual productivity features to make creating Razor views efficient, including IntelliSense, but you can use your favorite text editor to create the views.



Unit Testable. Unit testing Web form views is notoriously difficult, if not impossible, but Razor makes it easier. Not easy, but testing it doesn’t require a controller or Web server, and you can host it in any unit test project.

We’re not sure that Razor is as much fun as Microsoft seems to think it is, but it is certainly a big step up from the minutia needed to create a typical Web form. They’ve done a lot of usability work on the engine, and that work has helped make this first version of the engine a fine alternative to the Web forms engine. 4-4

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Views in ASP.NET MVC You can select which view engine to use when creating a new view in an MVC project. All of the features of a view in MVC are equally available in Razor as in the Web forms engine, and you can mix and match views using different engines in the same application. You can even write a full view with one view engine and partial views embedded within the full view in the other engine. This is analogous to being able to write any .NET application using either C# or VB. The syntaxes are quite different, but ultimately the code compiles to IL (intermediate language) code. Both the Web forms and Razor view engines render the same HTML sent to the browser. If you’re an old MVC dog that isn’t interested in learning any new view engine tricks, then you can be happily productive and stay with the ASP.NET Web forms view engine. But we’re betting that most people, once they see how clean and elegant their views are using Razor, will make the switch and never look back. It really is that good. NOTE

MVC 3 includes both the Web forms and Razor view engines, with Razor the default for new views. But like many other features in the MVC framework, you can plug in any view engine you want, or even write your own using the same features in the .NET Framework on which Microsoft built the built-in view engines. With a different view engine, you can use a completely different syntax for defining your views. For example, you could use XML templates and XSLT to transform them into HTML. There are several open source alternative view engines available, including Spark, NVelocity, Brail, and NHaml. Most of the time, however, you’re probably better off sticking with the default Razor view engine, unless you have a compelling reason to use another one.

Comparing the Web Forms and Razor View Syntaxes Whether you are coming to MVC 3 as a seasoned ASP.NET MVC pro or are a novice to this style of Web development, it can be useful to explore the syntaxes of the two view engines. If you’re new to MVC, it can provide some help in deciding which view engine you want to learn and use most often, since both are first class view engines in MVC 3. If you are experienced with earlier versions of MVC, or are an ASP.NET Web forms developer, it can be helpful to see how the two syntaxes differ. In this section, you’ll see how the two view engines implement the most common features of a Web page, and explore their differences. The fundamental difference between a Web forms view and Razor is the syntax used to embed code nuggets in a view. The Web forms view uses the following syntax for code nuggets, with an opening delimiters.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-5

Using MVC Views



Razor uses a simple @ symbol to designate code nuggets, like the following. Razor doesn’t require you to close the code block because it has semantic knowledge of the HTML and C# code within the nugget. Razor can identify the code within each nugget and implicitly close the block. This alone can save innumerable keystrokes in a view, and the @ symbol is much easier to type than the angle brackets and percent sign, often followed by a colon. And like the delimiters in the Web forms engine, @ will automatically encode the string placed in the HTML so you don’t have to do anything else to provide that kind of protection for an application. @Html.ActionLink("Register", "Register")

See LogOn.aspx in DogApp.sln in DogAppMVC2 folder

The standard Logon view in the Account controller of a project created using the MVC Web application project template in MVC 2 and 3 can show a good example of the difference between the two forms engines. The DogApp.sln solution in this chapter’s files was built using MVC 2 and the Web forms engine. Figure 2 shows the LogOn.aspx view, with some of the redundant code removed to save space on the page.

Figure 2. The LogOn view using the ASP.NET Web forms view engine.

4-6

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Views in ASP.NET MVC

See Logon.cshtml DogApp.sln

The DogApp.sln solution in this chapter’s files was built using MVC 3 and the Razor engine. Figure 3 shows the Logon.cshtml view, with some of the redundant code removed to save space on the page.

Figure 3. The LogOn view using the Razor view engine.

There are a number of differences between the views in Figure 2 and Figure 3: 

The Web forms view is defined in a LogOn.aspx file, using the .aspx file extension long used for Web forms. The Razor view is defined in LogOn.cshtml, with a custom Razor file extension. (The equivalent VB file extension is .vbhtml.)



The Web forms page has a Page directive at the top that identifies the language used in the page, the master page file, and the type of model object used in the view:



Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-7

Using MVC Views The Razor page has only an @model directive to identify the type of model object, as shown in the following code. It figures out the language from the file extension and the master page is defined elsewhere, as you’ll see later. @model DogApp.Models.LogOnModel

TIP:

If you prefer the full syntax of specifying that the WebViewPage object is of a specific type when using Razor, like in the Web forms engine, you can use the @inherits statement at the top of the view instead of @model. There really is no reason to use @inherits, particularly since it is a syntax that Microsoft introduced with a preview version of MVC 3. This puts it in the awkward position of providing backwards compatibility with a feature introduced in a pre-beta release.



As mentioned earlier, all code nuggets in the Web forms view use the delimiters, while Razor uses @. Notice how much cleaner and simpler the Razor view is as a result. By default, Visual Studio highlights both types of code nugget markers in yellow, making them stand out on the page.



The using block code is much cleaner in Razor. The Web forms code can only be described as busy:

...

While the Razor code is much cleaner and better reflects how the block is defined in a regular language code file, including the opening and closing curly brackets: @using (Html.BeginForm()) { ... }

4-8

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Views in ASP.NET MVC There are a few other things to notice about the Razor version of the page: 

You can delimit a regular code block using the @{ } syntax, like the following code that sets the view’s Title property. This code doesn’t insert a string into the HTML; it just executes a line of code. You can include as much code as you want in the code block, but the spirit of MVC suggests that views should keep it simple and completely focused on building the view rather than stealing code that really should be in the controller. Variable values stay in scope in all of the code blocks and nuggets on the page.

@{ ViewBag.Title = "Log On"; }



The following code is from the Index view of the Dog controller, using a foreach loop to run through all of the items in the Model. The code block has the @ marker to start the code, but from there on you’re just writing regular code interspersed with HTML markup. It knows that is part of the markup and not part of the code, for example. You only need to include another @ for each additional code statement. Again, this is much cleaner than the syntax for the Web forms engine, and much quicker to type.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-9

Using MVC Views

@foreach (var item in Model) { @item.Name @item.Gender @item.Age @Html.ActionLink("Edit", "Edit", new { id = item.ID }) | @Html.ActionLink("Details", "Details", new { id = item.ID }) | @Html.ActionLink("Delete", "Delete", new { id = item.ID }) }



If you ever have a situation where you nest HTML content within an if code block or loop, or any other code block, you can wrap the inner content of the code block in an HTML element, such as a span, to help Razor identify the beginning of a content block. If you don’t want to include any kind of wrapping tag, even a nonblock element like span, you can use the block as in the following code in GetDog.cshtml. Without the tags, the dog names run together without any whitespace.

@foreach (var item in Model) { @Ajax.ActionLink(item.Key, "GetDogDetails", new { id = item.Value }, new AjaxOptions { UpdateTargetId = "divResults" }) }

4-10

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Views in ASP.NET MVC

See Home \Index.cshtml

One other nice feature in Razor is server-side comments. This lets you comment out code or HTML so that the content of the comment is not part of the Web page delivered to the browser. Standard HTML has client-side comments delimited with as shown in the following code snippet, but even though the content won’t appear in the browser, a user who views the page source will see the content.

ASP.NET Web forms, and that view engine, have server-side comments using the syntax that doesn’t include the content as part of the Web page sent to the browser, like the following code.

The Razor syntax for server-side comments is the following. You can use this to comment out a single line or many, and you can use the Visual Studio Comment and Uncomment buttons to select a block of HTML and code and either comment it out or remove the comment block and leave the content in the page. @* This won’t appear in the Web page source. *@

TIP:

If you have an embedded @ within static content in the page, such as in an email address, Razor is smart enough to see that the @ doesn’t start off a code statement. But if you ever have a situation where what follows @ could be a code statement, but you want Razor to consider it content, just double up the @ marker and use @@ instead.

As you can see, the Razor syntax is quite elegant and saves many keystrokes over the course of developing even simple views. It will take some time to learn the syntax, as well as let go of old habits if you’ve been building pages using ASP.NET Web forms or MVC 1 or 2. But once you learn how to build pages, we’re confident that you’ll see how slick Razor is, and how efficient it is for development. Besides, it’s the default for all new views you add to a project. We believe that Microsoft made the right call to make Razor the default for new MVC 3 projects. This is the reason why we chose to write this course using the default Razor instead of the Web forms engine.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-11

Using MVC Views

Creating Views Creating a view template in an MVC application is not all that different from creating a dynamic HTML page using Web forms, although here we’ll use the Razor view engine syntax. The main difference is how you use data from a model and code in the view to generate the page sent to the client browser. In this section, you’ll learn how to create a view and add content to it in various ways. ASP.NET MVC in Visual Studio 2010 adds numerous tools to the development environment that simplify creating new MVC views. Most commonly you’ll create a view from a controller action method, but you can also create a new view manually in Solution Explorer.

Creating a View from a Controller Action Method See UsingViews.sln

The easiest way to create a new view is from an existing action method in a controller. If you right-click anywhere within the method there will be an Add View option on the pop-up menu. For example, if you do this within the Home controller’s Index action method, you’ll get the Add View dialog box shown in Figure 4. Here you can create a partial view for generating a user control, a strongly-typed view that uses an existing model class, and data scaffolding for different kinds of views, such as to create or edit model data. You can also opt to use a layout page—which is similar to master page in Web forms—for the new view and define the ID of the content place holder. You can also select the view engine, which is set to Razor by default. If you have other, third-party view engines installed that integrate with Visual Studio, the view engine drop down box will also list those engines.

Figure 4. The Add View dialog box for a new Index view in the Home controller.

4-12

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Views in ASP.NET MVC The benefit of creating a view from an action method is that the dialog box fills in some of the options for you, as well as places the new view file in the controller’s views in the project folder structure. Another big benefit is that if you opt to create a strongly-typed view and select a non-empty scaffold template, MVC will create most of the view code needed to view, create, edit, or delete data for the object. Even if you have to customize the code, that can be a huge time saver over writing the view from scratch. You can also right-click anywhere within the Views folder structure to create a new view in the selected folder. The only downside of this technique is that you’ll have to fill in the view name. And if you put it outside of the controller’s Views folder, you’ll have to supply a full or relative path name when returning a ViewResult from the action method, so that MVC can find the proper view. It makes things easier for you if you stick to the convention of placing views in the controller’s Views folder. The one exception is that if you create a view that more than one controller will share, you can put it in the Views\Shared folder. After MVC searches the controller’s views, it will look there for the view. But because views are almost always tightly bound to a controller, you’ll rarely share views across controllers. More commonly, you’ll share partial views across controllers, as covered later in this chapter. You’ll see plenty of examples of creating views using the Add View dialog box in this chapter and throughout the course. This is the way you should probably create most of your views, because the resulting page will already include a lot of the HTML and code you’ll need, particularly if you create a strongly-typed view, and Visual Studio will take care of putting the view in the right location in the project, the Views/ folder.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-13

Using MVC Views

Creating a View Manually You can also right-click anywhere in the project’s folders and select Add|New Item from the pop-up menu. Then within the MVC 3 templates, select any of the options for the Razor or Web forms view engine to create a view, layout, or partial page, as shown in Figure 5. A Razor partial page is similar to a Web forms user control.

Figure 5. Create a view manually.

If you select the MVC 3 View Page (Razor) template, you’ll create an empty .cshtml view page with the following content. Notice that there is no statement binding the view to a model; if you need such a binding you’ll have to add the code manually. Unlike a Web forms view, the view doesn’t need to explicitly inherit from System.Web.Mvc.ViewPage. And if you’ve placed the view in a non-standard location (outside of the controller’s Views folder), you’ll have to provide the path to the view when an action method invokes it, and keep that path updated if you move the file within the project.

4-14

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Views in ASP.NET MVC

@{ Layout = null; }







The tools in Visual Studio are designed to help you observe convention over configuration, such as by placing new code files in the conventional location. You can almost always override those locations, but the significantly increased work is virtually never worth it, and your code will be less maintainable. So until you know MVC well, and only with a very good reason to violate the convention, you’d be well advised to not fight Visual Studio.

Layout Pages One of the great features in ASP.NET Web forms that helps keep all the pages in a site consistent is master pages. You can define one or more master pages with one or more content areas, then reference a master page in each child page and add just the content that changes for each child page. Razor provides the same support for consistent pages with its layout pages feature. Like master pages, a layout page is a template for the site where you define the common page content. See Shared/ _Layout.cshtml in DogApp.sln

An application created from the ASP.NET MVC 3 Web Application project template created with any but the Empty template includes a _Layout file in the Views/Shared folder. This is the page that defines the template for the site. As you can see in the following code (which has the script references omitted), it includes the HTML header information, including the CSS stylesheets and script files needed by the pages in the site, as well as the overall content for each page in the site. You can include any static content you want, as well as code that will execute for each page. The location for the content of the view

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-15

Using MVC Views that will fill in the content of the requested URL is at the @RenderBody() statement towards the bottom of the layout page. @ViewBag.Title ... My MVC Application @Html.Partial("_LogOnPartial") @Html.ActionLink("Home", "Index", "Home") @Html.ActionLink("About", "About", "Home") @RenderBody()

4-16

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Views in ASP.NET MVC Then you can reference the layout page in any view in the application by setting the ViewPage’s Layout property to the file name of the layout page, as shown in the following code. The rest of the view only needs to generate the content that MVC will insert at the location of the RenderBody method. @{ Layout = "~/Views/Shared/_Layout.cshtml"; }

But it can be a pain to remember to reference the layout page in every view in an application. So the sample application puts the previous code into a _ViewStart file in the /Views folder, which will execute the code for every view in the application. You’ll learn more about this special _ViewStart file in the next section. You can also define multiple sections within a layout using a RenderSection method in the layout file, and defining named sections in each view. You can even designate whether a section is optional.

Running Code Before a View Sometimes you need to have code that runs before a view’s code runs. Maybe you need to perform some kind of configuration action or, in the case of a standard MVC application, you want to use a standard layout file for every view. For this kind of code before a view scenario, you can simply place a file with the name _ViewStart.cshtml in the /Views folder of a project. See Views/ _ViewStart.cshtml

The following code shows the version of this file created by every MVC application, using either of the two Visual Studio MVC 3 project templates, Internet and Intranet. This sets the Layout property to the master shared layout file for every view in the application so that you don’t have to set the property in every view. You can place any other code you want into this file to run before every view. For example, if you want to apply different layouts to different views based on some external criteria, such as time of day, you could put that code in this file. @{ Layout = "~/Views/Shared/_Layout.cshtml"; }

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-17

Using MVC Views The _ViewStart file in the /Views folder affects every view in the application, including all subfolders, but you can also put a version of the file in any subfolder of /Views as well. That version of _ViewStart will then have precedence over the one in the root /Views folder, but only for views contained within that subfolder and any subfolders below it. For example, the _ViewStart file in the /Views/Dog folder in the DogApp project will contain code that runs before any view in the Dog controller only. The Razor view engine is a bit strange at first, particularly if you are coming to MVC from ASP.NET Web forms. But the syntax is easy to learn, and it takes much less effort to write a view. Even if it seems just too foreign to consider, give it a try in a couple of simple projects, then use the view engine that works best for you. And remember two things: you can combine views from different view engines in the same project, and there are third-party alternative view engines available that you might like better.

4-18

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View

Adding Content to a View See the Content controller and views in UsingViews.sln

At its heart, ASP.NET is a framework for building dynamic Web pages and delivering them to users. The user gets a page consisting of HTML, and maybe some other Web standard content such as CSS and JavaScript. You can include static HTML in the view file and provide dynamic content either using clientside JavaScript (and maybe Flash, Silverlight, etc.) or server-side code. In this chapter you’ll focus on using server-side code to provide dynamic content. There are a variety of ways to provide a combination of static and dynamic content to a view, and in the following sections you’ll learn about some of the most common ways to add content to a view.

Static View Content All of the static, unchanging content that will appear in a Web page created from a view should be included as static HTML within the view definition. This will result in the best performance for a page, since the application doesn’t have to do any view processing on the server. See Content Controller.cs

The Static() action method, shown as follows, in the Content controller is just about the simplest way to invoke a view. The Static view is named the same as the action method, and the Static.cshtml file is located in the Content controller’s Views folder. As a result of following those conventions, all the code needs to do is call the View() method to instantiate the associated view. public ActionResult Static() { return View(); }

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-19

Using MVC Views

See Views/Content/ Static.cshtml

The Static view is quite simple as well, containing only a bit of static HTML and content.

Company Profile AppDev is a technical learning company nationally recognized for providing in-depth, real-world content in multiple formats to developers, IT professionals and computer users. Headquartered in Minneapolis, AppDev offers training in a variety of formats including CD-ROM, DVD-ROM, AppDev OnDemand™, and KSource Online Learning™. Instructor-led courseware licensing is also available through AppDev Technical Publishing.

Figure 6 shows the result of invoking the Static action method and displaying the Static view. There is nothing very exciting here, but it does show that you can easily build static pages into an MVC Web site. Most sites have at least a few static pages, and MVC accommodates them nicely.

Figure 6. Static content in a view.

4-20

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View

Content Result At the other extreme from a view that consists entirely of static content, you can also use a ContentResult object to entirely define the content of a Web page within an action method. Strictly speaking, this isn’t a feature of MVC views, since there is no view involved in this technique. But when you need to create a Web page that has to be entirely dynamic, this is a good option. A ContentResult has three properties. Content takes the content you want to display, ContentEncoding defines the encoding of the content, and ContentType tells the browser what the content consists of so that it can render it correctly to the user. Common settings for the content type are text/plain, text/xml, and application/json, but there are many others. See Content Controller.cs

For example, say you have some XML data in a file on the server that you want to send to the browser as XML and let the browser deal with displaying it. One way to do this is to read the data from the file in an action method, and use a ContentResult to send it to the browser, like this: public ContentResult ReadHamlet() { string fileName = Server.MapPath(@"~\Content\Hamlet.xml"); TextReader tr = new StreamReader(fileName); string contents = tr.ReadToEnd();

return Content(contents, "text/xml"); }

TIP:

Hamlet.xml and Hamlet.dtd are located in the Content folder in the project. This is the conventional location for static files like this that provide content used in views and Web pages.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-21

Using MVC Views When you invoke the ReadHamlet action method, the raw XML of the entire play Hamlet displays in the browser. If you use Internet Explorer or another browser that understands XML you can collapse and expand different sections of the play, as shown in Figure 7.

Figure 7. Hamlet displayed as XML in the browser.

WARNING!

The Hamlet.xml file is about 300K, so it is likely that it will take a few moments to load into the browser window.

The important thing to understand about using ContentResult is that you define the entire contents of what the Web page will display. Alternatively, you can provide data for updating a portion of a page, such as when the page makes an Ajax request for JSON data.

Inline Code One of the easiest ways to populate a view with data—and probably one that you’ll use often in your MVC applications—is to use a model and name/value pairs. The controller’s action method is responsible for providing the data to the view, before invoking it. To read and display the data in the view, you can use inline code using the Razor @ notation for code nuggets. You can use a code nugget to evaluate results and include simple, user interface-based logic in a view.

4-22

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View If you have experience with ASP.NET Web forms, it may seem wrong to use code nuggets like this. A Web form is a hierarchy of server controls, and using inline code is a bit of an aberration that hearkens back to the spaghetti code of classic ASP and server-side VBScript. But think of a view as a template for a Web page: a bunch of text that the browser will use to display a Web page to a user. As long as the code nuggets are strictly limited to user interface logic, you’re adhering to the principle of separation of concerns to keep your code clean, simple, and maintainable. A well designed and implemented MVC application can optimize application efficiency and maintainability. See Models\ Person.cs

Say that you have a Person class as defined in the following code. This defines a model that you’ll use within a view to hold information about a person and the dogs they have as a generic list of strings.

public class Person { public int ID { get; set; } public string Name { get; set; } public string Email { get; set; } public string Phone { get; set; } public DateTime Birthdate { get; set; } public List Dogs { get; set; } }

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-23

Using MVC Views

See Content Controller.cs

The following code defines the GetPerson action method that initializes the Person class with data, then passes the person object to the View method that creates a ViewResult. Using an object as a parameter this way assigns the object to the Model property of the ViewData object, which makes it the model for the view. The code also creates an updated object in ViewData using a ViewBag, which is a convenient way to pass individual bits of data to the view that are not part of the model. It is important to understand that all of the data, model and updated value, will pass from the controller to the view using the ViewData object. public ViewResult GetPerson() { Models.Person person = new Models.Person() { ID = 1, Name = "Don", Email = "[email protected]", Phone = "907-555-1212", Birthdate = new DateTime(1977, 04, 01), Dogs = new List { "Mardy", "Izzi", "Jewel" } }; ViewBag.Updated = DateTime.Now;

return View(person); }

See GetPerson.cshtml

Then in the view you can make use of that model and the updated key/value pair in ViewData, as you can see in the following code. By passing person to the View method, it gets assigned to the Model property of the ViewPage object. That lets you reference the person object using strongly-typed properties, such as Model.Dogs. You can reference the updated value using ViewBag, as in the last line of the following code. Notice that the code casts the updated value as a DateTime so that it can call the ToShortTimeString() method. TIP:

We created the GetPerson view using the Add View dialog box from the action method. In the dialog box, we selected to create a strongly-typed view using the Person class, and left the scaffold template set to Empty.

4-24

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View

Get Person Information: @Model.Name

Email: @Model.Email Phone: @Model.Phone Birthdate: @Model.Birthdate.ToShortDateString() @Model.Name has these dogs: @foreach (var dog in Model.Dogs) { @dog.ToString() }

Last updated: @(((DateTime)ViewBag.Updated).ToShortTimeString())

In order to display the update time on the page, the controller passes a DateTime object to the updated value in ViewBag, then the view casts it back to a DateTime and calls a method of that type, ToShortTimeString(). You instead could have converted the time to a string in the controller, and just passed that string to the view. But unless there is a reason to do otherwise, it is best to let the view handle displaying the data in the format that makes sense for the user interface. It’s a small detail, but doing it in the view makes for a cleaner separation between the concerns of controllers and view. Of course, you can also just directly use a DataTime object in the view without passing it from the controller, which reveals that the previous example is a bit contrived. WARNING!

The statement in the previous code that displays the updated time has what appear to be an extra set of parentheses around the entire statement. This is an example of one of the cases where Razor doesn’t quite parse the change from C# code to HTML markup and content. Without the outer parentheses, Razor sees only “((DateTime)ViewBag.Updated)” as code, and displays an unformatted date and time string followed by “.ToShortTimeString()” as literal text on the Web page.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-25

Using MVC Views Figure 8 shows the page when you run the application.

Figure 8. Viewing the GetPerson view.

4-26

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View

A Word about ViewData ViewData is actually a property of the base WebViewPage object from which an MVC Razor page derives. That property returns a ViewDataDictionary object that functions as the data conduit between a controller and a view. ViewBag is a dynamic object wrapper around ViewData, letting you create and use properties on the fly. It has two ways of passing data: Dictionary: You can assign name/value pairs to the ViewDataDictionary, like the updated value used to send the current date and time to the view. Then you can read the value in the view, casting it as necessary for display to the user. The name is a string, the value is an object. Strongly typed model: You can assign a single object to the ViewData’s Model property, which lets you access the object as its own type without needing to cast the object in the view before you can use it. In the view, you use the Model property of the ViewPage, which returns the object stored in the ViewData in the controller. You can combine these two uses of ViewData however you want in any action method, giving you plenty of flexibility in how you pass data from the controller to view. How you use the model in a view depends on whether you create a strongly-typed view or a loosely-typed view. If your view includes an @model directive as in the code below, it is strongly-typed. If it is loosely typed, the Model property returns just an object, which isn’t very useful.

@model UsingViews.Models.Person

Visual Studio will set up these page directives for you if you use the Add View dialog box to create the view, depending on whether you opt to create a strongly- or looselytyped view. The controller doesn’t know or care whether the view is strongly- or loosely-typed.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-27

Using MVC Views

HTML Helper Methods Writing inline code using code nuggets gives you a lot of control over the HTML that is sent to the browser in response to a controller action. But it can quickly become tedious writing the same elements over and over, plugging in code nuggets for attributes and element content. So MVC comes with a large number of HTML helper methods, or just HTML helpers, which generate some of the most common markup you’re likely to include in a page. They provide a tighter, more concise syntax for generating HTML based on data the view gets from the controller. Best of all, they are flexible enough to adapt to different conditions of the environment and data in which the view is generating a Web page. It is tempting to think of HTML helpers as controls, similar to ASP.NET server controls. But they really are just shortcuts to generating HTML in a view. A view exposes HTML helpers through the Html property of the WebViewPage class. This property exposes an HtmlHelper object, and that’s what you use in a view. See Content Controller.cs

The UsingViews project includes two Create() action methods in the Content controller that lets you create a new person, then redirects to the Index view of the Home controller. The following code doesn’t do anything with the new Person object, but that doesn’t matter. The focus here is on the view. public ActionResult Create() { return View(); }

[HttpPost] public ActionResult Create(Models.Person person) { if (!ModelState.IsValid) { return View("Create", person); }

// Store the person object somewhere

return RedirectToAction("Index", "Home"); }

4-28

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View

See Views/Content/ Create.cshtml

What’s interesting here is the following view. The view uses several HTML helpers—BeginForm, ValidationSummary, LabelFor, EditorFor, and ValidationMessageFor—to generate HTML in the Web page. In this simple example, the view creates a set of input elements that is linked to the Person object by name when the user posts the data back to the server. We’ve omitted a couple of script elements that reference JavaScript code files needed for client-side validation. Create

@using (Html.BeginForm()) { @Html.ValidationSummary(true) Person @Html.LabelFor(model => model.Name) @Html.EditorFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name)

@Html.LabelFor(model => model.Email) @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email)

@Html.LabelFor(model => model.Phone) @Html.EditorFor(model => model.Phone) @Html.ValidationMessageFor(model => model.Phone)

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-29

Using MVC Views

@Html.LabelFor(model => model.Birthdate) @Html.EditorFor(model => model.Birthdate) @Html.ValidationMessageFor( model => model.Birthdate)

}

@Html.ActionLink("Back to List", "Index")

Here is the resulting label and text box for the Name property, taken from the page source when the application runs. The data-* attributes are HTML 5-style attributes that the browser doesn’t process or attempt to interpret, which you can use for application data. Here the attributes are included to support clientside validation. Name

4-30

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View Admittedly, the resulting HTML is not very complex, and the HTML helper methods don’t provide a huge savings in typing or any big functionality benefits. But most of the HTML helper methods are overloaded so that you can define additional attributes as well as additional settings specific to each type of helper. For example, the BeginForm helper method emits opening and closing form tags to wrap a form, automatically creating the correct action attribute value based on the appropriate action method. There are helper methods that support data validation as well. And it gets even better: the templated versions of helper methods, available for most of the basic helper methods, can read the data type of a model property and display the appropriate HTML. For example, you could use such a templated helper to automatically display a date picker control for all date and time types. This is the extent that you’ll explore HTML helper methods in this chapter, but there is plenty more to learn about them.

Partial Views ASP.NET Web forms let you create reusable chunks of a Web page using user controls, implemented in an .ascx file. You can drop these into any Web form in the application and have, for example, a consistent login control that appears wherever you need it. It’s a great way to avoid duplicating the same chunk of HTML code, markup, and server-side code in many places throughout an application, with the attendant problems of duplicate code. An MVC application has the same kind of feature, called a partial view, which supports MVC’s principle of keeping things DRY: Don’t Repeat Yourself. Partial views provide a great way to reuse HTML, content, and code in a variety of views instead of duplicating the same code repeatedly. Like regular views, you can have strongly- and loosely-typed partial views. See the Create and Edit views in DogApp.sln

One of the ways you can use a partial view is to consolidate the duplicate code in Create and Edit views. The code in these two views is often identical, other than the name of the submit button and maybe other links on the page. The following Create view lets you create a new Dog object (with some of the fields removed to save space). The contiguous code that it shares in common with the Edit view is highlighted. As you can see, it is most of the view. This is a prime candidate for refactoring out into a partial view. And you can even go further and include the submit button if you change the value to Save instead of Create or Edit.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-31

Using MVC Views

Create

@using (Html.BeginForm()) { @Html.ValidationSummary(true, "Please correct the following problems:") Dog

@Html.LabelFor(model => model.Name) @Html.EditorFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name)

@Html.LabelFor(model => model.Gender) Female @Html.RadioButtonFor( model => model.Gender, "Female") Male @Html.RadioButtonFor( model => model.Gender, "Male") @Html.ValidationMessageFor(model => model.Gender)

...

@Html.LabelFor(model => model.Notes) @Html.TextAreaFor(model => model.Notes, 5, 40, null) @Html.ValidationMessageFor(model => model.Notes)

4-32

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View }

@Html.ActionLink("Back to List", "Index")

Like views, you should put partial views in one of two places. If the partial view will be shared by views in a single controller, such as the Dog controller, you should put them in Views\Dog. If you’ll share them in views in more than one controller, put the partial view in Views\Shared. MVC will automatically search those two locations for the view. If you put the partial view anywhere else, you’ll have to specify the path to the partial view file when you use it in a view. You can create a new partial view by right-clicking the Dog folder under Views in Solution Explorer and selecting Add View from the pop-up menu. To create the DogForm partial view in the sample application, we used the options shown in Figure 9. Notice that the partial view is strongly-typed on the Dog object, just like the original Create and Edit views were.

Figure 9. Creating a partial view to create or edit the Dog object.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-33

Using MVC Views This creates an empty view with nothing but the @model directive: @model DogApp.Models.Dog

Then it’s just a matter of cutting the redundant code from either the Create or Edit view and pasting it into the new DogForm partial view. The following code is the completed partial view, again with a few of the fields removed. Other than changing the value attribute of the submit button, this is the exact same code from the Create or Edit view. @model DogApp.Models.Dog

@using (Html.BeginForm()) { @Html.ValidationSummary(true, "Please correct the following problems:") Dog

@Html.LabelFor(model => model.Name) @Html.EditorFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name)

@Html.LabelFor(model => model.Gender) Female @Html.RadioButtonFor( model => model.Gender, "Female") Male @Html.RadioButtonFor( model => model.Gender, "Male") @Html.ValidationMessageFor( model => model.Gender)

4-34

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View ... @Html.LabelFor(model => model.Notes) @Html.TextAreaFor(model => model.Notes, 5, 40, null) @Html.ValidationMessageFor(model => model.Notes) }

See Views\Dog\ CreatePV.cshtml

Now all the Create and Edit views have to do is use the Html.Partial helper method to access that partial view. This is the new, greatly simplified code in the CreatePV view:

Create

@Html.Partial("DogForm")

@Html.ActionLink("Back to List", "Index")

When you run the application, the EditPV and CreatePV views look and behave exactly the same as the original Edit and Create views, other than the changed text on the submit button. And you can use the DogForm partial view anywhere in the application where you need to edit a Dog object or create a new one. Best of all, if you ever find that you need to change the form, all you have to do is change the partial view, and all the views that use it will automatically use the new form. By default, a partial view shares the same ViewData with its parent view. The RenderPartial helper method has an overload that lets you pass a different model. In that case, the partial view will only have access to that passed model, not the parent’s model. That’s a great way to partition the data the partial view has to work with. Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-35

Using MVC Views

See Views\Dog \DogInfo.cshtml

You can also render a partial view for each item in a collection, which is one way to make use of a different model for the partial view. Say that you wanted to be able to list all the Dog items in a collection in a bulleted list instead of the table generated in the Dog controller’s Index view. You could define a DogInfo partial view like the following code. It takes a Dog object and creates a statement about the dog’s age, including adjusting whether years is plural or not. The partial view is strongly-typed on a Dog object, as you can see in the @Control directive in the inherits attribute. @model DogApp.Models.Dog

@Model.Name is @Model.Age year@(Model.Age == 1 ? "" : "s") old!

See Views\Dog\ List.cshtml

Then you could use the partial view in a List view like the following code. Notice that the view is strongly typed to the generic List of dogs defined in the Dog controller, not a collection like the List view. The Partial method passes a dog object as the second parameter, which becomes the model for the partial view, and blocks the parent’s model, the collection of dog objects. (The TitleContent element is not included here.) @model IEnumerable

@{ ViewBag.Title = "List"; }

List

@foreach (var dog in Model) { @Html.Partial("DogInfo", dog) }

4-36

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View When you run the application with the default list of dogs, and perhaps add a one-year-old dog, you can click the List Info link on the Dog controller’s Index view, or navigate directly to /Dog/List. Figure 10 shows the resulting view.

Figure 10. Using the DogInfo partial view in a loop.

This approach can be quite a bit simpler than using some of the complex server controls of an ASP.NET Web forms application. Partial views are one of many ways that MVC applications can rival the power of Web forms. TIP:

There is a RenderPartial helper method as well as the Partial method used in this section. RenderPartial writes directly to the response output stream instead of returning a string as Partial does. RenderPartial may result in a better performance in a high-volume Web site, but requires that you wrap the method call inside a Razor code block, which makes it a bit harder to use. Otherwise, the two methods are largely identical. You should normally use Partial for the convenience, unless you need to wring the maximum performance out of a site.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-37

Using MVC Views

RenderAction Components Sometimes it makes sense to use application logic to generate just a portion of a view. This is most useful when you want to display dynamic information on a page that is unrelated to the other dynamic content on the page. In that case, the data you need for the portion of the view isn’t part of the model. Maybe it comes from an entirely different source, such as stock or weather data on a page that displays store locations in a selected metro area. Or you might want to implement a navigation component on the page that has some kind of complicated logic to decide what options to display to a user at a particular point, maybe based on recent user actions or permissions. Or it could display a user’s shopping cart contents as she navigates your product catalog. The possibilities are unlimited. There are many scenarios when it is useful to be able to write application logic in the controller to generate the data and then inject the data into the response stream to the view, outside of the rendering of the HTML for the main portion of the page. The RenderAction helper method calls into a controller method and then injects the action method’s output into the response stream. You can pass whatever parameters you want from the view to the action method in order to customize the response. If you stop and think about this a bit, it might seem a bit strange. A view calling into a controller? Is a view supposed to even know about controllers? Well, views and controllers aren’t entirely decoupled, maybe not as much as you would want them to be, for purity’s sake. A trivial example that you’ve seen throughout this course is when a view contains an ActionLink method call to produce a link into a controller action method. The view needs to know what action methods are available in order to create the link. That sort of thing doesn’t include any application logic, however, so RenderAction is definitely a step up from that. But what is actually happening with RenderAction is that the view is asking the controller for data to display on the resulting Web page. In a way, it is a variation of letting the controller provide a model to the view, except with RenderAction the view is making the request outside of the initial instantiation of the view.

4-38

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View Let’s take a look at an example of how to use RenderAction. The Dog See controller has an action method called RenderList. Imagine that this method DogController.cs in does some sort of complicated process to extract some information outside the DogApp.sln main scope of the application. Let’s simulate that by using the dogs object already defined in the controller. This is the action method that the main view will call using RenderAction. public ViewResult RenderList() { // Used with RenderAction return View(dogs); }

See Views\Dog\ RenderList.cshtml

The RenderList partial view, shown as follows, produces a bulleted list of dogs, using the DogInfo partial view you saw earlier in the chapter. The code displays a header and then loops through the dog collection passed to it as the model by the previous RenderList action method. This is the component that you can drop into any view in the application. The code sets the Layout property to null to not again include the layout page elements, such as the Home and About tabs. @model IEnumerable

@{Layout = "";}

Render Dog List @foreach (var dog in Model) { @{Html.RenderPartial("DogInfo", dog)} }

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-39

Using MVC Views The RenderList partial view generates the result of using RenderAction to call the RenderList action method. The last piece of the solution is the action method and view that makes the call to the RenderList action method. This is the RenderActionView action method and its accompanying view. The following code is for RenderActionView. Notice that it passes no ViewData or model to the view at all. public ViewResult RenderActionView() { // The main view to display return View(); }

The following code is the RenderActionView view. Note that it has some static content, then calls RenderAction to drop the content generated by the RenderList action method into a particular location on the page. That call causes the RenderList action method to return a snippet of HTML to the view. @{ ViewBag.Title = "RenderActionView"; }

RenderActionView

This view uses a RenderAction to display a list of dogs, using the RenderList partial view, which in turn uses the DogInfo partial view. @{Html.RenderAction("RenderList", "Dog")}

4-40

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View Figure 11 shows the result of running the application and clicking a link to the Dog controller’s RenderActionView action method, accessed from the List Info using RenderAction link on the Dog controller’s Index view.

Figure 11. The resulting view, displaying the dog list using RenderAction.

Let’s recap what happens when the user clicks the link that executes the RenderActionView action method, /Dog/RenderActionView. 1. The RenderActionView action method executes, which causes the RenderActionView view to load. 2. The RenderActionView view begins rendering the page, and eventually gets to the RenderAction method call. 3. RenderAction calls the RenderList action method in the Dog controller, which passes the dogs collection to the RenderList partial view. 4. The RenderList partial view takes the dog data and generates a bulleted list of dogs, using the DogInfo partial view to generate the string information for each dog. 5. The partial view generated from the RenderList action method is inserted into the stream of HTML in the RenderActionView view, and the list of dogs appears within the Web page. What’s important here is not that the code uses nested partial views to generate content—although that is very cool and efficient—but that by using RenderAction you can insert content into a page. You’re not limited to HTML either; you can insert almost any kind of content you want.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-41

Using MVC Views RenderAction is a very powerful feature of MVC applications. But remember that with great power comes great responsibility. It is an easy feature to abuse, and can easily result in a convoluted application with controllers and views calling each other in highly unmaintainable ways. So be careful with it! Use it where it makes sense, but nowhere else.

4-42

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View

Summary 

Views are the windows into your application, responsible for creating the user interface and sending requests to the controller.



You have control over the HTML an MVC application generates, but there are plenty of tools to help with the job.



ASP.NET Web forms and MVC applications share the same default view engine, the WebForms view engine, built on the WebFormViewEngine class.



MVC 3 adds a second view engine, called Razor, with a streamlined, efficient syntax.



You’re not limited to using the built-in view engines. You can substitute an open source engine, or write your own.



You can create a new view directly from the controller action method or by creating it in any folder in Solution Explorer.



By convention, views should go in the Views folder, or in the shared folder if it is used by multiple controllers.



ASP.NET is a framework for building dynamic Web pages, and MVC provides many methods of creating dynamic content.



You can include static content in a view; in fact, a view can be entirely made up of static content.



ContentResult lets you dynamically create the entire response to a user request.



You can include inline code in a view using code nuggets starting with @, which let you access ViewData from the view.



ViewData is a property of the view, and lets you use either dictionary semantics or the Model property to send data from the controller to the view.



HTML helper methods generate common HTML markup, and are able to make use of model and ViewData.



Partial views let you create reusable user controls to avoid repeating the same HTML and code throughout an application.



RenderAction lets a view call a controller action method to return content to the view.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-43

Using MVC Views

(Review questions and answers on the following pages.)

4-44

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Adding Content to a View

Questions 1. What is a major difference between an MVC view and a Web form? 2. Why should you consider using the Razor view engine, even if you are familiar with Web forms? 3. What is normally the best way to create a new view? Why? 4. When might you want to use a ContentResult instead of a view? 5. How can you use ViewData to send data to a view? 6. How do you implement a partial view?

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-45

Using MVC Views

Answers 1. What is a major difference between an MVC view and a Web form? Views give you complete control over the HTML generated, whereas Web forms consist of a hierarchy of server controls that spew HTML.

2. Why should you consider using the Razor view engine, even if you are familiar with Web forms? The Razor view engine is compact, expressive, and fluid; it is easy to learn; it is based on HTML with C#, you can create it in any text editor, and, unlike Web forms views, Razor views are unit testable. Besides, it’s cool!

3. What is normally the best way to create a new view? Why? Right-click within the controller action method to open the Add View dialog box. This pre-populates the dialog box with some settings and places the view in the correct place in the project.

4. When might you want to use a ContentResult instead of a view? When you want to dynamically generate the entire content sent as a response to the user, especially if the content is not HTML.

5. How can you use ViewData to send data to a view? There are two ways: using dictionary semantics to store name/value pairs and with the Model property to create a strongly-typed model.

6. How do you implement a partial view? By using the Add View dialog box and selecting “Create as a partial view”, adding the content, then calling it with Partial in the parent view.

4-46

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Lab 4: Using MVC Views

Lab 4: Using MVC Views

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-47

Lab 4: Using MVC Views

Lab 4 Overview In this lab you’ll learn how to create and work with MVC views. To complete this lab, you’ll need to work through two exercises: 

Create a View Using ViewData and Code Nuggets



Create and Use a Partial View

Each exercise includes an “Objective” section that describes the purpose of the exercise. You are encouraged to try to complete the exercise from the information given in the Objective section. If you require more information to complete the exercise, the Objective section is followed by detailed step-bystep instructions.

4-48

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Create a View Using ViewData and Code Nuggets

Create a View Using ViewData and Code Nuggets Objective In this exercise, you’ll create an MVC model to store information about a store, including name, location, hours, and a rating. You’ll then add code to an action method in the Home controller of the application to create a store object and add a Message value to ViewData. You’ll then create a strongly-typed view to display the message and store details.

Step-by-Step Instructions 1. Start Visual Studio 2010 and create a new MVC application using the ASP.NET MVC 3 Web Application project template. Name the project ViewsLab and put it in a convenient location. The New Project dialog box should look like Figure 12. Click OK to create the project.

Figure 12. Creating the new ViewsLab project.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-49

Lab 4: Using MVC Views 2. In the New ASP.NET MVC 3 Project dialog box, select the Internet Application template, the Razor view engine, and the Use HTML5 semantic markup option. Don’t create a test project. The dialog box should look like Figure 13. Click OK.

Figure 13. Setting options for the new project.

4-50

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Create a View Using ViewData and Code Nuggets 3. Create a Store model by right-clicking the Models folder in Solution Explorer and select Add|Class from the pop-up menu to open the Add New Item dialog box. In the dialog box, change the name of the class to Store.cs as shown in Figure 14. Click Add to create the class and open it in the code editor.

Figure 14. Creating the Store model.

4. Add a using statement for a reference to the DataAnnotations namespace using the following code. using System.ComponentModel.DataAnnotations;

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-51

Lab 4: Using MVC Views 5. Change the definition of the Store class to define the following properties along with their data validation annotations. The Name, Location, and Hours properties are required, and the value for Rating, if provided, must be from 1 to 5. public class Store { [Required(ErrorMessage="Store name is required")] public string Name { get; set; }

[Required(ErrorMessage = "Store location is required")] public string Location { get; set; }

[Required(ErrorMessage = "Hours of opening are required")] public string Hours { get; set; }

[Range(1, 5, ErrorMessage = "Enter a rating from 1 to 5")] public int Rating { get; set; } }

6. Compile the project by selecting Build|Build ViewsLab from the Visual Studio main menu. Correct any errors that occur. 7. Return to the Home controller code file. If it is not already open in the Visual Studio code editor, double-click the Controllers\HomeController.cs code file in Solution Explorer. 8. In the Index() action method, change the string value assigned to the Message value in ViewBag to the following: ViewBag.Message = "Welcome to our Store!";

9. Add code to instantiate a Store object, which will function as the model for the Index view. Add the following code immediately after the ViewBag assignment and before the return statement:

4-52

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Create a View Using ViewData and Code Nuggets

Models.Store store = new Models.Store() { Name = "Fairbanks Mercantile", Location = "2nd and Main", Hours = "8 AM to 9 PM Daily", Rating = 4 };

10. Add the following line of code to assign the new store object to the Model property of the ViewData object, immediately after the last code you added. This will make the store object available as a model to a stronglytyped view. ViewData.Model = store;

11. Since the Index view already exists in the Home controller, you’ll need to create a new Store view. First, change the call to the View() method in the Index action method to tell it to use the Store view instead: return View("Store");

12. The complete Index() action method should look like the following: public ActionResult Index() { ViewBag.Message = "Welcome to our Store!";

Models.Store store = new Models.Store() { Name = "Fairbanks Mercantile", Location = "2nd and Main", Hours = "8 AM to 9 PM Daily", Rating = 4 }; ViewData.Model = store; return View("Store"); }

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-53

Lab 4: Using MVC Views 13. Next, add a view to display the store. Right-click the Views/Home folder in Solution Explorer and select Add View from the pop-up menu to open the Add View dialog box. 14. Change the View name setting to Store. Check the Create a stronglytyped view check box, and select Store (ViewsLab.Models) from the Model class drop-down list. Select Details from the Scaffold template drop-down list. The dialog box should look like Figure 15. Click Add to create the view and open it in Visual Studio.

Figure 15. Creating the Store view.

15. Examine the code in the Store.cshtml file. Notice that Visual Studio has used the view template to write code that reads the properties of the store object, using the Model property, to display the data. 16. Change the contents of the element near the top of the code file to display the Message value stored in ViewBag. Use this code: @ViewBag.Message

4-54

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Create a View Using ViewData and Code Nuggets 17. Return to the Home controller code file and press F5 to run the application. Because you changed the application’s default action method—Index() in the Home controller—the details for the store should appear in the opening page, as shown in Figure 16. Make sure that the header is correct and that the details for the store are correct.

Figure 16. Viewing the Store view.

18. Close the browser window to end execution.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-55

Lab 4: Using MVC Views

Create and Use a Partial View Objective In this exercise, you’ll remove the display code from the Store view you created in the previous lab exercise, and use it to create a reusable partial view called DisplayStore.

Things to Consider Where should you put the new partial view file? Since this will be used by the views in a single controller, it is best to put it with that controller’s view files. In this case, that would be Views/Home.

Step-by-Step Instructions 1. Continue to work with the project from the first lab exercise (or start with the project in the ViewsLab_ex02 folder). 2. Start by creating the Display partial view. Right-click on the Views/Home folder in Solution Explorer and select Add|View from the pop-up menu to open the Add View dialog box. 3. Name the view DisplayStore. Check the Create as a partial view check box. Make sure that the Create a strongly-typed view check box is checked and that Store (ViewsLab.Models) is selected for the Model class. Leave the other default settings so that the dialog box looks like Figure 17.

Figure 17. Creating the partial view.

4-56

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Create and Use a Partial View 4. Click Add to create the view and open it in Visual Studio. The entire contents of the file should consist of the @model directive: @model ViewsLab.Models.Store

5. Open the Views/Home/Store.cshtml file. Select the entire element, including its open and closing tags and contents, and press CTRL+X to cut it to the Clipboard. 6. Return to the DisplayStore.cshtml file and paste the code from the Store view below the @ model directive. The entire partial view should now look like the following: @model ViewsLab.Models.Store

Store

Name @Html.DisplayFor(model => model.Name)

Location @Html.DisplayFor(model => model.Location)

Hours @Html.DisplayFor(model => model.Hours)

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-57

Lab 4: Using MVC Views Rating @Html.DisplayFor(model => model.Rating)

TIP:

You can press CTRL+K+D to tidy up the DisplayStore partial view, reformatting the code according to the rules defined in Tools|Options|Text Editor HTML for formatting HTML. You can customize those rules to suit your preferences.

7. Return to the Store.cshtml file. Add the following code immediately after the element to invoke the DisplayStore partial view: @{ Html.RenderPartial("DisplayStore"); }

8. Return to the Home controller code file and press F5 to execute the application. The Store view should again appear as in Figure 18. This is unchanged from the previous lab except that now the store display information is contained in a reusable partial view.

Figure 18. Viewing the Store view, new and improved with a reusable partial view.

4-58

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

Create and Use a Partial View 9. Close the browser window to end the application.

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.

4-59

Lab 4: Using MVC Views

4-60

Building ASP.NET MVC 3 Applications Using Visual C# 2010 Copyright © by Application Developers Training Company All rights reserved. Reproduction is strictly prohibited.