1. Page Types
The SharePoint presentation layer is delivered using a
virtual path provider that forwards requests to the SharePoint server
object model for processing. As part of the processing pipeline, content
is either retrieved from an appropriate database or loaded from disk.
Often, the final output is a combination of the two. Bearing this
processing model in mind, we can broadly group the content delivered by
the SharePoint presentation layer into two groups: application pages and
site pages.
Application Pages
Application pages are loaded from disk and usually
provide common user interface functionality such as site administration
and configuration tools. Application pages can be found in the file
system at %SPRoot%\Template\Layouts. To facilitate the sharing of
application pages among sites, this folder is mounted on every web site
as http://<web site url>/_layouts.
Site Pages
Site
pages are often loaded from a content database and include all other
pages that are not included in the application pages group. All
user-generated content is delivered using site pages. Although site
pages are often loaded from a content database, when sites are created
from a site definition or pages are added to a site by feature
activation, the default version of the page is usually loaded from the
file system. A common example of this is the default master page that is
provisioned for each site. In reality, this page exists in the file
system as v4.master, but the provisioning process mounts the file as
default.master in the master pages gallery for each site.
Within the site pages group are a few types of site pages: web part pages, standard pages, master pages, and page templates.
Web Part Pages
The functionality and user interface delivered via
web part pages predominantly comprise web part zones that users can
populate with web parts. A web part is a
server control that users can add to a web part page using a
browser-based interface. Web parts allow users to customize and
configure a page without having to resort to developer tools such as
Visual Studio.
Keep in mind that although site pages are loaded from
a database, web parts and their user interfaces are not. Only the
configuration of the web part is stored in the database. Commonly, a web
part is installed on each web server and is loaded in much the same way
as any server control. Much of the user interface functionality of the
SharePoint platform is implemented via web parts, and as a result, most
of the pages that are provided out of the box fall into the web part
page category.
Standard Pages
All other types of web pages delivered by the
SharePoint platform can be considered standard pages. For all intents
and purposes, a standard page is equivalent to a page that could be
created using any web design tool. Commonly, standard pages use
SharePoint master pages to include common user interface elements such
as navigation, but this is not a requirement.
Master Pages
Essentially, the master pages that are used by SharePoint 2010 are the
same as any other ASP.NET master pages—except to support some of the
built-in functionality, SharePoint master pages must include a number of
specific placeholders.
Page Templates
Page templates are an
essential part of the Enterprise Content Management (ECM) functionality
of SharePoint 2010. You construct content pages by using a page template
to define the positioning and presentation of data that is retrieved
from individual fields in a document library.
2. Ghosting/Unghosting
As
you’ve seen, two main page types are featured in SharePoint:
application pages that are rendered from the file system, and content
pages that are usually rendered from the database. However, pages are
often rendered using a number of additional files such as master pages
or page templates. Some of these components, while mounted in document
libraries, are actually being loaded from the local file system.
When changes are made to these files using SharePoint
Designer, the changed page content is stored within the content
database. As a result, all future renderings of the page will be
retrieved from the content database. Site pages that are loaded from the
file system are known as ghosted pages, and when these pages have been customized they are known as unghosted pages.
With each new version of SharePoint comes another set of terms for this phenomenon. SharePoint 2003 brought us ghosting/unghosting; SharePoint 2007 scrapped these terms in favor of the more descriptive uncustomized/customized. Now with SharePoint 2010, the terms attached and detached are used to prevent any ambiguity. In most SharePoint documentation, the terms ghosted/unghosted are still in use, however.
In SharePoint 2010, a few new
tools enable administrators and developers to better manage
ghosted/unghosted pages. When editing pages, SharePoint Designer now
loads the page content in safe mode by default. In this mode, parts of
the page that are loaded from the file system are highlighted and can’t
be edited. To make changes to these regions, you must work in Advanced
mode.
3. Executing Server-Side Code
Another difference between site pages and application
pages is the way they are parsed by the SharePoint platform.
Application pages behave like any other ASP.NET page in that they can
contain inline server-side code; however, site pages are rendered using
the safe mode parser that prevents inline server-side code from
executing. This makes sense when you think about it, because site pages
are commonly user-generated, and allowing inline server-side code to
execute would present a major system stability risk.
If this were the whole story, SharePoint would be
somewhat limited as a development platform. Of course, functionality can
be implemented in the form of web parts, and although this is commonly
the best approach, in some situations it’s vital to be able to handle
the various events within the ASP.NET page rendering process—for
example, when you want to change the master page dynamically.
Two solutions are possible to this problem: the first
solution, which is recommended only in exceptional circumstances, is to
add a PageParserPath entry to the web.config file, like this:
<SharePoint>
<SafeMode ...>
<PageParserPaths>
<PageParserPath VirtualPath="/myFiles/*" CompilationMode="Always"
AllowServerSideScript="true" IncludeSubFolders="true"/>
</PageParserPaths>
Be careful when you’re adopting this approach, because it effectively allows users to execute arbitrary code on the server.
A better approach is to create a code-behind class and deploy it to the farm. You can then change the Page directive for any page to refer to the code-behind file, as shown:
<%@ Page language="C#" MasterPageFile="~masterurl/default.master"
Inherits="MyAssembly.MyClass,MyAssembly" %>
Using SharePoint Designer, create a new blank site at the URL http://<Your server name>/Example.
From the Site tab, select Document Library | Document Library. Name the new library MyCustomPages.
Using
Visual Studio, choose File | New | Project. Then select Empty
SharePoint Project from the New Project dialog, as shown. Name the
project Example.
Set the site to use for debugging to the blank site that we set up in step 1. Select the Deploy As Farm Solution option.
After the project has been created, choose Project | Add New Item. Add a new Module named MyCustomPages, as shown:
At
the time of writing, no template is available for creating site pages
with code-behind, and when using a SharePoint project, standard ASP.NET
pages are not available in the Add New Item dialog. To get around this
limitation, we’ll add an application page and then modify it to suit our
needs. Choose Project | Add New Item. Select Application Page and name
the file MyCustomPage.aspx, as shown:
Since
application pages are always located in the Layouts folder, Visual
Studio has automatically created a mapping to the SharePoint Layouts
folder and added our new page to a subfolder named Example. Because
we’re creating a site page rather than an application page, drag the
MyCustomPage.aspx file into the MyCustomPages folder, and then delete
the Layouts folder since it’s no longer required.
In the MyCustomPage.aspx file, add the following markup:
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register TagPrefix="SharePoint"
Namespace="Microsoft.SharePoint.WebControls"
Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="WebPartPages"
Namespace="Microsoft.SharePoint.WebPartPages"
Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, →
PublicKey Token=71e9bce111e9429c" %>
<%@ Register TagPrefix="Utilities"
Namespace="Microsoft.SharePoint.Utilities"
Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, →
PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="asp" Namespace="System.Web.UI"
Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, →
PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, →
PublicKeyToken=71e9bce111e9429c" %>
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="MyCustomPage.aspx.cs" Inherits="Example.MyCustomPage"
MasterPageFile="~masterurl/default.master" %>
<asp:Content ID="PageHead"
ContentPlaceHolderID="PlaceHolderAdditionalPageHead"
runat="server">
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain"
runat="server">
<asp:TextBox ID="TitleText" runat="server"/>
<asp:Button ID="Button1" runat="server" Text="Change Title" OnClick="Button1_OnClick"/>
<table width="100%" cellpadding="0" cellspacing="0" →
style="padding: 5px 10px 10px 10px;">
<tr>
<td valign="top" width="70%">
<WebPartPages:WebPartZone runat="server"
FrameType="TitleBarOnly" ID="Left" Title="loc:Left">
<ZoneTemplate>
</ZoneTemplate>
</WebPartPages:WebPartZone>
 
</td>
<td>
 
</td>
<td valign="top" width="30%">
<WebPartPages:WebPartZone runat="server"
FrameType="TitleBarOnly" ID="Right" Title="loc:Right">
<ZoneTemplate>
</ZoneTemplate>
</WebPartPages:WebPartZone>
 
</td>
<td>
 
</td>
</tr>
</table>
</asp:Content>
<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle"
runat="server">
My Custom Page
</asp:Content>
<asp:Content ID="PageTitleInTitleArea"
ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea"
runat="server">
<asp:Label ID="MyLabel" runat="server" Text=""></asp:Label>
</asp:Content>
In the MyCustomPage.aspx.cs file, add the following code:
using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
namespace Example
{
public partial class MyCustomPage : WebPartPage
{
protected void Page_Load(object sender, EventArgs e)
{
MyLabel.Text = "Hello World";
}
protected void Button1_OnClick(object sender, EventArgs args)
{
MyLabel.Text = TitleText.Text;
}
}
}
Since
we’re deploying our page to a document library, we need to make a few
modifications to the Elements.xml file in the MyCustomPages folder.
Change the XML as follows:
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="MyCustomPages" Url="MyCustomPages">
<File Path="MyCustomPages\MyCustomPage.aspx" Url="MyCustomPage.aspx"
Type="GhostableInLibrary" />
</Module>
</Elements>
We can now build and deploy the project to SharePoint. Choose Build | Deploy.
Using the browser, navigate to http://<your server url>/Example/MyCustomPages/MyCustomPage.aspx to see the results:
Click
the Change Title button to modify the title that’s displayed on the
page, confirming that our code-behind works as expected.
If we select Edit Page from
the Page tab, we’ll also be able to add web parts to our page. In fact,
reviewing the options available on the Page tab, we can see that our
custom page effectively behaves in the same way as any other site page,
allowing us to set permissions or execute workflows.