Before diving into the details of how Web Part pages work, two important aspects of their architecture must be noted. First, support for customizing and personalizing Web Parts is available in site pages but not in application pages, thus giving site pages a clear design advantage over application pages.

        <p>
        Second, adding and customizing Web Parts does not require customizing the Web Part pages that host them. A Web Part page defines Web Part zones but does not define what goes inside these zones. Instead, all of the data for tracking Web Part instances and their customization and personalization data are kept in separate tables inside the content database. This means that a Web Part page can remain in a ghosted state even though users are continually adding, customizing, and personalizing the Web Parts within its zone.
        </p>

        <p>
        Web Part pages in a WSS 3.0 site are built on top of the new Web Part infrastructure introduced with ASP.NET 2.0. To create a Web Part page in an ASP.NET 2.0 application, you must create an .aspx page that contains exactly one instance of a control named WebPartManager and one or more WebPartZone controls. The WebPartManager is responsible for managing the lifetime of Web Part instances as well as serializing Web Part–related data so that they can be stored and retrieved from the tables in the ASP.NET services database.
        </p>

        <p>
        The Web Part infrastructure of WSS 3.0 does not use the standard WebPartManager control from ASP.NET. Instead, WSS relies on a specialized control named SPWebPartManager that derives from the ASP.NET 2.0 WebPartManager control. The SPWebPartManager control overrides the standard behavior of the WebPartManager control to persist Web Part data inside the WSS content database instead of inside the ASP.NET services database.
        </p>

        <p>
        In most cases, you don’t have to worry about dealing with the SPWebPartManager control directly because the one and only required instance of the SPWebPartManager is already defined in the standard default.master page. When you create a site page that links to default.master, the SPWebPartManager control is automatically added to the page. Therefore, you simply need to add one or more WebPartZone controls.
        </p>

        <p>
        Two things must be done when creating a page template for a Web Part page. The first is to inherit from the WebPartPage class that is defined inside the Microsoft.SharePoint.dll assembly. The second is to add one or more WebPartZone controls. Note that you must use the WebPartZone control defined by the WSS team and not the one of the same name defined by the ASP.NET team.
        </p>

        <p>
        To add WebPartZone controls to a page template, you must add a Register directive that imports all of the controls from the Microsoft.SharePoint.dll assembly defined in the Microsoft.SharePoint.WebPartPages namespace as shown in the following page template definition.
        </p>


        <pre data-sub="prettyprint:_">
        <%@ Page MasterPageFile="~masterurl/default.master"
        Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage,
        Microsoft.SharePoint, [full 4-part assembly name]"
        meta:progid="SharePoint.WebPartPage.Document" %>

        <%@ Register Tagprefix="WebPartPages"
        Namespace="Microsoft.SharePoint.WebPartPages"
        Assembly="Microsoft.SharePoint, ..." %>

        <asp:Content ID="main" runat="server" ContentPlaceHolderID="PlaceHolderMain" >

        <h3>Custom Web Part page</h3>

        <table width="100%">
        <tr>
        <td valign="top" style="width:50%">
        <WebPartPages:WebPartZone ID="LeftZone" runat="server"
        FrameType="TitleBarOnly"
        Title="Left Web Part zone" />
        </td>
        <td valign="top" style="width:50%">
        <WebPartPages:WebPartZone ID="RightZone" runat="server"
        FrameType="TitleBarOnly"
        Title="Right Web Part zone" />
        </td>
        </tr>
        </table>
        </asp:Content>

</pre>

        <p>
        It is easier to create pages that host Web Parts in the WSS framework than in the ASP.NET Framework. For example, when you design an ASP.NET application that involves Web Parts, you are required to add logic to each page that interacts with the WebPartManager control to manage the display mode. It is also necessary to explicitly add controls, such as Editor Zones and Catalog Zones, to the page so that users can customize existing Web Parts as well as add new Web Parts.
        </p>

        <p>
        Fortunately, you don’t need to worry about managing the display mode or adding Editor Zones and Catalog Zones when creating Web Part pages for WSS. When you create a Web Part page that inherits from the WebPartPage class, all of this work is done for you behind the scenes. The Site Actions menu automatically provides the Edit Page command that allows the user to enter a mode for adding and customizing Web Parts.
        </p>

        <p>
        In the CustomSitePages project, three different site pages are provisioned from the page template named WebPartPage.aspx. If you navigate to the first site page named WebPartPage01.aspx and select the Edit Page command from the Site Actions menu, you will see that there are two empty zones, as shown in Figure 3-7. At this point, you can use basic WSS support to add a new Web Part instance as you would to any other Web Part page, such as default.aspx.
        </p>

        <p>
        When you provision a Web Part page from a page template, it initially contains no Web Parts in any of its Web Part zones. While you could rely on users manually adding Web Parts to your pages, it is more convenient and reliable for you to use a technique in which you prepopulate Web Part zones with whatever Web Parts your business solution requires.
        </p>
        <p>
        There are two common techniques for adding a Web Part instance to a Web Part zone. The first technique involves a declarative approach used inside a feature in which you define an AllUsersWebPart element inside a File element. The following example demonstrates the File element that is used in the CustomSitePages project to provision the Web Part page named WebPartPage02.aspx.
        </p>


        <pre data-sub="prettyprint:_">
        <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
        <Module Path="PageTemplates" Url="SitePages" >
        <File Url="WebPartPage.aspx" Name="WebPartPage02.aspx" Type="Ghostable" >
        <!-- Add a Web Part to left zone -->
        <AllUsersWebPart WebPartZoneID="LeftZone" WebPartOrder="0">
        <![CDATA[
        <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2"
        xmlns:iwp="http://schemas.microsoft.com/WebPart/v2/Image">
        <Assembly>Microsoft.SharePoint, ...</Assembly>
        <TypeName>Microsoft.SharePoint.WebPartPages.ImageWebPart</TypeName>
        <FrameType>None</FrameType>
        <Title>Watch My Gears Run</Title>
        <iwp:ImageLink>/_layouts/images/GEARS_AN.GIF</iwp:ImageLink>
        </WebPart>
        ]]>
        </AllUsersWebPart>
        </File>
        </Module>
        </Elements>

        </pre>


        <p>
        As you can see, a File element can contain an inner AllUsersWebPart element that references a target Web Part zone and includes serialized data for the Web Part instance to be created. We will revisit the inner WebPart element in more detail in Chapter 4 when we discuss Web Part description files.
        </p>
        <p>
        The second technique for adding a Web Part instance to a Web Part page involves writing code against the WSS object model. An example of this type of code is supplied in the FeatureActivated event handler for the CustomSitePages project. The code obtains a reference to the SPFile object associated with WebPartPage03.aspx and uses an SPLimitedWebPartManager object to add a new Web Part instance to a particular target zone.
        </p>


        <pre data-sub="prettyprint:_">
        public override void FeatureActivated(
        SPFeatureReceiverProperties properties) {
        // acquire objects for site, page and limited Web Part Manager
        SPWeb site = (SPWeb)properties.Feature.Parent;
        SPFile page = site.GetFile("SitePages/WebPartPage03.aspx");
        SPLimitedWebPartManager mgr;
        mgr = page.GetLimitedWebPartManager(PersonalizationScope.Shared);
        // add Web Part to Right Zone
        ImageWebPart wp1 = new ImageWebPart();
        wp1.ChromeType = PartChromeType.None;
        wp1.ImageLink = @"/_layouts/images/IPVW.GIF";
        mgr.AddWebPart(wp1, "RightZone", 0);
        }
        </pre>

        <p>
        The advantage to using the first technique is that Web Parts can be added to pages with declarative logic in the same place where the actual page is being provisioned. The advantage of using the second approach involving code is that it is more flexible. While you can execute code that adds a Web Part instance during feature activation, you can also execute the same code long after the feature is activated. For example, imagine a scenario in which you would like to write the code required to enumerate through every site within a farm to add a special Web Part to a target zone on every home page. The WSS object model makes it possible to automate this type of administrative task with Web Part pages.
        </p>