Let’s start with a brief description of Site Pages from MSDN:
Site pages are provisioned from a template page that is stored on the file system of the front-end Web server. When a site is provisioned, SharePoint Foundation creates a pointer to the instance of the page template on the file system. This allows SharePoint Foundation to avoid repeatedly creating copies of the pages, which are provisioned each time a site is created. When a user customizes a site page, the template for the page is then stored in the content database. The page is retrieved from the content database every time it is requested by a user. A customized page can, however, be reset to the original template page through the Web browser or a tool such as SharePoint Designer.To paraphrase, we are going to create an ASPX page that will be deployed to the SharePoint system folders – this is the page template. Then, we will use a Module element to provision page instances into a SharePoint site (i.e. the SharePoint content database). Once a page instance has been added to a site, an end user can modify the markup of the page using SharePoint Designer. Because end users can modify the markup, inline code is not allowed in Site Pages.
Let’s Get Started
I show something similar to the following in my SharePoint 2010 Fundamentals course on Pluralsight but that demo is broken into two pieces and some find it a little hard to follow. This walkthrough shows the full process from end-to-end. The steps work the same in both Visual Studio 2010 or 2012 and targeting both SharePoint 2010 and 2013. I’ll be using Visual Studio 2010 and targeting SharePoint 2010.Update: I've uploaded a video version of this walthrough to YouTube. The video is embedded at the bottom of this post.
Creating the Project
- In Visual Studio, click File | New | Project…
- In the New Project dialog, select the Visual C# > SharePoint > 2010 node under Installed Templates.
- Select the Empty SharePoint Project template, set the Name to SitePageDemo and click OK.
- In the SharePoint Customization Wizard, enter the site you want to use for debugging, select Deploy as a farm solution, and click Finish.
Adding the Site Page
- In the Solution Explorer, right-click on the project and select Add | New Item and select Application Page. Leave the default name and click Add. We don’t actually need this page but we can use the generated markup.
- In the Solution Explorer, right-click on the project and select Add | New Item and select Module. Set the name to SitePages and click Add.
- In the Solution Explorer, right-click on the Sample.txt file under SitePages and select Rename. Change the name of the file to MyPageTemplate.aspx. You can ignore the warning about changing the file extension.
- Open or switch to ApplicationPage1.aspx and copy all of the markup in the page to the clipboard
- Open or switch to MyPageTemplate.aspx, remove any text currently in the file, and then paste the contents of the clipboard into the file
As mentioned previously, Site Pages do not support inline C# or VB code. So we need to modify the markup to remove any indication that we might be trying to do so. If we don’t, SharePoint’s Safe Mode Parser will throw an exception when we try to load the page.
- Remove the Import directives at lines 2 and 6
- Change the Page directive to the following
<%@ Page Inherits="SitePageDemo.SitePages.MyPageTemplate" MasterPageFile="~masterurl/default.master" %>
- Add a Button and a Label to the Main content. You will likely need to close and re-open the file to be able to use the Toolbox.
- Change the text in the PageTitle content to My Site Page
- Remove the PageTitleInTitleArea Content Control
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %> <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=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" %> <%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Page Inherits="SitePageDemo.SitePages.MyPageTemplate" MasterPageFile="~masterurl/default.master" %> <asp:Content id="PageHead" runat="server" contentplaceholderid="PlaceHolderAdditionalPageHead"> </asp:Content> <asp:content id="Main" runat="server" contentplaceholderid="PlaceHolderMain"> <asp:Button id="Button1" runat="server" text="Button" /> <br /> <br /> <asp:Label id="Label1" runat="server" text="Label"></asp:button> </asp:content> <asp:Content id="PageTitle" runat="server" contentplaceholderid="PlaceHolderPageTitle"> My Site Page </asp:Content>
Adding the Code-Behind
When building a Site Page we need to use true code-behind, not the code-beside we’ve been using since ASP.NET 2.0. We are going to need to add the code for the event handlers plus add all the code that would normally be generated by the WebForms designer. The class we are about to create is “linked” to the markup by the Inherits attribute of the Page directive.- In the Solution Explorer, right-click on the project and select Add | Class. Set the name to MyPageTemplate.cs and click Add.
- Add Using statements for System.Web.UI and System.Web.UI.webControls
- Make the class public and have it inherit from System.Web.UI.Page
- Create protected fields (i.e. class-level variables) for the Button and Label that we added in the markup of the page. The variable names in the code must match the ID attributes of the controls in the markup.
- Add an event handler for Page_Init. We will attach control event handlers here.
- Inside Page_Init, register an event handler for the Click event of the button.
- In the Click event handler, set the Text property of the Label to the current time
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.UI; using System.Web.UI.WebControls; namespace SitePageDemo.SitePages { public class MyPageTemplate : Page { protected Button button1; protected Label label1; protected void Page_Init(object sender, EventArgs e) { button1.Click += new EventHandler(Button_Click); } protected void Button_Click(object sender, EventArgs e) { label1.Text = System.DateTime.Now.ToLongTimeString(); } } }
Provisioning the Page Instance
We’ve just finished the page template, now we need to provision the page instance. One of the files that was created when we added the SitePages Module was an element manifest. This file (elements.xml) contains the instructions that will provision the page instance. In it we will tell SharePoint to copy the template into a folder names SitePages and using the file name MyPage.aspx. We’ll also indicate that this page can be customized by end-users by setting the Type to Ghostable.- Open or switch to elements.xml and update the attributes of the File element to look like the following:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Module Name="SitePages"> <File Path="SitePages\MyPageTemplate.aspx" Url="SitePages/MyPage.aspx" Type="Ghostable" /> </Module> </Elements>
Feature
We want to ensure that the Feature that contains the SitePages module has a meaningful title.- In the Solution Explorer, double-click on Feature1 to open the Feature Designer
- Change the Title to Add Custom Site Pages
Safe Control Entry
I mentioned the Safe Mode Parser previously. In addition to checking for inline code it will also check to see if the class that implements the code-behind for the site page has been marked as safe to execute. We indicate a class is safe to execute by adding a Safe Control entry into the Web.config file for the SharePoint Web Application. This seems like it might be tricky but it’s actually quite easy, the solution package deployment mechanism does most of the hard work for us.- In the Solution Explorer, select the SitePages folder
- In the Properties Window, select the Safe Control Entries property. A button with an ellipses should appear.
- Click the ellipses button to open the Safe Control Entries dialog
- Click the Add button in the bottom-left of the dialog to add a new Safe Control Entry
- Change the Type Name property to MyPageTemplate (i.e. the name of the class that implements to code-behind for the page)
- Click OK to close the Safe Control Entries dialog
Cleanup
We no longer need the Application Page we created earlier so we can delete it along the with its associated folders.- In the Solution Explorer, right-click on the Layouts folder and select Delete. We want to delete this folder and its contents so click OK when the confirmation dialogs shows.
Deploy and Test
We are now ready to test our work.- In the Solution Explorer, right-click on the project and select Deploy. This creates and deploys the solution package to SharePoint. By default, deploying from Visual Studio also activates the Feature that provisions an instance of our page.
- Navigate to the SharePoint site you are using for testing
- Add SitePages/MyPage.aspx to the site URL and press Enter
- Click the button on the page and the label should show the current time
Comments