ASP.NET master pages and Facelets templating

 

Introduction

Templating is the feature in Web technologies to define complex layouts for the Web applications. Templating enables the creation of common structure and look and feel across all the pages in the Web application. A template does not define the content; rather it defines placeholders for contents and provides the layout, orientation, flow, functionality, structure and logical organization of the elements of the Web site. For example, one popular layout places a navigation menu and logos on the left side or the top of the site, a copyright notices on the bottom of the site, and the content in the middle. This might be difficult to maintain a standard look if you always put the common pieces in places with every web page. So using a templating solution, you enable to separate the content from the presentation of the content as well as providing a solution which is flexible and easy to maintain.

In this article, I will illustrate how to implement templating solutions using Facelets templating and ASP.NET master pages.

Templating solution with ASP.NET master pages

Through the concept of master page, ASP.NET technology implements its own templating solution. A master page is a page which comprises tags and controls shared across all the pages of the Web solution. Master pages contain placeholders known as ContentPlaceHolders where the content from child pages will go. When the user requests the content of a page, then ASP.NET merges the output of the content of the child pages with the output of the master page.

Now let’s illustrate the master pages concepts with an example. For this solution, we’re going to use Visual Studio.NET 2008 and ASP.NET MVC which my favorite framework to develop Web applications in Microsoft.NET technologies, although these concepts can be applied to Web forms as well.

Open Visual Studio.NET 2008 and select the File | New | Project menu option. The click on the ASP.NET MVC application (see Figure 1).

Figure 1

By default, the ASP.NET MVC application contains the definition of nice master page. You can reach to this master page by opening the Site.Master file in the Views | Shared directory (see Figure 2).

Figure 2

When you open this page, you can notice the followings:

  • All the master pages have .master extension and the Master directive (@Master) (highlighted in yellow in the Listing 1).
  • They define the site layout to ensure consistent look and feel. That is, the header with common logos and menu, the content area and the footer (hightlighted in turquoise in the Listing 1).
  • They group common features by containing top-level HTML elements such as <html>, <head>,<title>, <body>, common script codes, references to common CSS (styles), scripts, and common pages, etc (highlighted in bright green in the Listing 1).
  • They use of ContentPlaceHolder to place the content from the child pages. In this case, we’re going to print the title and the main content for each page (highlighted in gray in the Listing 1).
<%@ Master Language=”C#” Inherits=”System.Web.Mvc.ViewMasterPage” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”&gt;

<html xmlns=”http://www.w3.org/1999/xhtml”&gt;

<head runat=”server”>

<title><asp:ContentPlaceHolder ID=”TitleContent” runat=”server” /></title>

<link href=”../../Content/Site.css” rel=”stylesheet” type=”text/css” />

</head>

<body>

<div>

<div id=”header”>

<div id=”title”>

<h1>My MVC Application</h1>

</div>

<div id=”logindisplay”>

<% Html.RenderPartial(“LogOnUserControl”); %>

</div>

<div id=”menucontainer”>

<ul id=”menu”>

<li><%= Html.ActionLink(“Home”, “Index”, “Home”)%></li>

<li><%= Html.ActionLink(“About”, “About”, “Home”)%></li>

</ul>

</div>

</div>

<div id=”main”>

<asp:ContentPlaceHolder ID=”MainContent” runat=”server” />

<div id=”footer”>

</div>

</div>

</div>

</body>

</html>

Listing 1. Site.Master master page

Next step is to create the content page. In this case, our solution follows the MVP architecture, so we right-click on the Controllers folder and select the Add | Controller option from the context menu and create a test controller (see Figure 3).

Figure 3

Next step is to right-click on the Index action method of the test controller and select the Add View option from the context menu. Then the Add View dialog box appears where you can select the master page for this view (the Select master page field) and content placeholder (the ContentPlaceHolderID field) (see Figure 4).

Figure 4

Content pages are standard ASP.NET pages with the followings:

  • They contain the Page directive with the MasterPageFile attribute pointing to the master page associated to this content page (highlight in yellow in the Listing 2).
  • They only contain markup, script codes and other HTML elements inside the Content controls. If you try to place these elements outside the Content controls, you will receive the following compile error ““Only Content controls are allowed directly in a content page that contains Content controls” (highlighted in gray in the Listing 2).
<%@ Page Title=”” Language=”C#” MasterPageFile=”~/Views/Shared/Site.Master” Inherits=”System.Web.Mvc.ViewPage” %>

<asp:Content ID=”Content1″ ContentPlaceHolderID=”TitleContent” runat=”server”>

This is the title

</asp:Content>

<asp:Content ID=”Content2″ ContentPlaceHolderID=”MainContent” runat=”server”>

<h2>This is the content header</h2>

<div>This is the content.</div>

</asp:Content>

Listing 2. The example content page

Regarding to the Content controls, it’s remarkable to say that:

  • Each Content control maps to exactly one ContentPlaceHolder control in the master page using the ContentPlaceHolderID attribute of the Content control and the ID attribute of the ContentPlaceHolder control.
  • You do not need to define a content control for every ContentPlaceHolder control in the master. If a Content control doesn’t exist for a place holder, the master page will simply render the default content inside of the ContentPlaceHolder of the master page.
  • You can also write content page itself as master page. This is very useful when the application is broken into multiple modules and we want to inherit a common look and feel. The only thing to do is to page the Page directive for the Master directive (see Listing 3).
<%@ Master Title=”” Language=”C#” MasterPageFile=”~/Views/Shared/Site.Master” Inherits=”System.Web.Mvc.ViewPage” %>

Listing 3

Another thing to notice is that when the content pages and their underlying master page are in different directories, the relative path in URL will be not correct. In order to solve this problem, we need to use absolute URLs to the master page.

You can also access to the master page from the content page by using the Master property of the Page class. This is very important to change the master page programmatically.

Now let’s run the example, and you will see that the page title has changed as well as the main content (see Figure 5).

Figure 5

Templating solution with Facelets

Now we’re going to implement a templating solution for the J2EE world using Facelets. I want to say that I’ve shown Facelets technology as my templating framework because of its similarities to the principles of ASP.NET master pages. Although, you can find a lot of templating frameworks in the J2EE world such as Tiles, Velocity, Freemarker, Groovy, Sitemesh, etc.

The first step in learning the principles of Facelets is to find an analogy with the principles of ASP.NET master page. It’s remarkable to say that the Facelets <ui:insert/> tag is similar to ASP.NET <asp:ContentPlaceHolder/> tag in the master pages. The master pages are called templates (I like this term more) in Facelets. In order to fill the templates in JSP pages (this is equivalent to call the master page from a content page), you need to start with <ui:composition/> tag that points to the template file. This is roughly equivalent to declaring the MasterPageFile attribute in an ASP.NET page. Inside the <ui:composition/> tag, you use <ui:define/> tag to override the template defaults, similar to the way an <asp:Content/> tag is used. These elements can contain any kind of Web items.

The following example can be tested in any Web application using JSF (Java Server Faces) in the presentation layer.

The first step is to download the Facelets distribution and unzip it. Then copy the jsf-facelets.jar library into the WEB-INF/lib directory of your Web application.

Next step is to add the Facelet init parameter to the web.xml file. This step assumes that you already have a working JSF Web application. Then you edit the existing web.xml page by adding the following parameter in the Listing 4.

<context-param>

<param-name>javax.faces.DEFAULT_SUFFIX</param-name>

<param-value>.xhtml</param-value>

</context-param>

Listing 4

This specifies to the JSF engine to assume a prefix of xhtml. Our JSF pages should have the file extension .xhtml and you can have a servlet mapping ‘*.jsf’ files for the faces servlet. In that way, the actual page test.xhtml can be accessed as test.jsf.

And the final step to configure the Facelets framework is to add the FaceletViewHandler. Modify faces-config.xml and set com.sun.facelets.FaceletViewHandler as the view handler. (This will override the default view handler setting which is expecting JSP file formats) (see Listing 5).

<application>

<view-handler>

com.sun.facelets.FaceletViewHandler

</view-handler>

</application>

Listing 5

Next step is to create a template for the application by creating the master.xhtml page in the /WEB-INF/templates directory by defining the Facelets namespace, the title content placeholder, and main area content placeholder (see highlighted in gray in the Listing 6).

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns=http://www.w3.org/1999/xhtml
      xmlns:ui=http://java.sun.com/jsf/facelets>
<head>
  <title><ui:insert name="title">Default title</ui:insert></title>
</head>
<body>

<div id="main_area">
  <ui:insert name="content">
  </ui:insert>
 </div>

</body>
</html>

Listing 6

Now a content page is defined by shown in the Listing 7 (highlighted in gray).

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

  <ui:composition template="/WEB-INF/templates/master.xhtml">
  <ui:define name="title">This is the title of test page 1</ui:define> 
  <ui:define name="content"> 
     <h2>This is the head of content</h2>
     <div>This is the content of the test page 1</div> 
  </ui:define> 
</ui:composition>

</html>

Listing 7

Conclusion

In this article, I’ve shown how to implement templating solutions using Facelets templating and ASP.NET master pages. Now, you can use this solution to your own business problems.