Developing application pages for SharePoint can be challenging. This blog post provides guidance on some methods that I use to make the development process easier.

Application Pages?

When developing applications on the Microsoft Office SharePoint Server 2007 (MOSS) framework, there are several available ways to surface functionality to the user via the user interface (UI). The possibilities include web parts, publishing pages, application pages, custom list and site definitions, InfoPath forms, custom field types, etc. Each has its place, with advantages and disadvantages inherent in each.

When developing pages that need to be accessible from any site in the SharePoint farm, often the best choice is to create Application Pages. Application pages are .aspx pages that reside in the _layouts folder on each web front-end server, and can be accessed from any site within SharePoint by using the /_layouts virtual folder (for example http://Server/SiteCollection/Site/_layouts/MyPage.aspx). The pages are usually used for administration pages to this end, and in some cases this is the only option (for example when adding a custom action to the settings page for a site or a content type, unless hard-coding the link, application pages are the only viable option)

Challenges

Standard pages such as web part pages or publishing pages automatically inherit all the style and master page settings from the site they are located in, and usually just need web parts or controls to be dragged on to the page. Developing application pages, however, can be more challenging for the following reasons:

-          The pages pick up their context from SharePoint and the virtual root, which means they have to be developed and accessed within the layouts folder in order to access the local site context

-          In order to render correctly, the pages need to pick up the correct master page, which is referenced by relative path only. Again, this means they need to be developed and accessed from within the layouts relative root to have the correct look and feel

-          If the pages rely on an assembly (dll) behind the scenes to hold the code, the assembly needs to reside either in the GAC or in the virtual root bin folder (usually C:\Inetpub\wwwroot\VirtualDirectories\wss\*PortNumber*\bin) which makes deployment more complex.

 

 

Development

If the pages that are being developed are relatively simple, they can be written as pure inline .aspx pages, with no code behind file or referenced assembly. This means that they can be developed and debugged within the _layouts folder, and deployment is relatively simple with a feature wrapped in a solution package. When developing pages that need proper compiled assemblies to run, development is slightly trickier.

From experience I have found that the following three development options are available, depending on the requirements of the project.

1.       Simple (inline) aspx page

2.       Copying into _layouts and bin folders at build

3.       Create a dummy master page

 

 

1.       Simple (inline) aspx page

This is the simplest way to develop application pages, and is useful only for the simplest pages (based on the difficulty in debugging the code in the page). Each page consists primarily of HTML within the content placeholders, with any functional code being kept to a minimum and coded inline on the page. An example of this type of page can be found here.

The advantage of this type of development is that it is very quick and easy to get up and running. The obvious disadvantage is that the pages must be kept very simple as coding large blocks of code inline is prone to errors, and it is very difficult to debug.

 

2.       Copying into _layouts and bin folders at build

The idea behind this strategy is to create a normal Web project, but as post-build events you copy the aspx and assembly files into the correct location. The process for setting up a project for this type of development is as follows:

1.       Create a normal Web project

2.       Rename the aspx page to the page name of your choice, and modify it to reference the correct master page and to use content placeholders as per the MSDN documentation here.

3.       Add post-build steps to:

a.       Copy the aspx page into a sub-folder in the LAYOUTS folder in the 12 hive (for example, C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\MyProjectName\MyPage.aspx)

b.      EITHER

 

copy the dll file into the correct bin folder for the relevant web application (C:\Inetpub\wwwroot\wss\VirtualDirectories\MyWebAppPort\bin)

OR

 

Add the assembly into the GAC using gacutil

4.       Set the Startup type (under the Web tab in the project properties in Visual Studio 2008) to “Start Url:” and set the URL to http://MyWebApp/_layouts/MyProjectName/MyPage.aspx)

This will allow you to develop and then test by hitting the “F5” key. To debug, attach to the correct w3wp process (you can attach to all of them if there are multiple entries and you are unsure which one to attach to) and then browse to the correct URL (http://MyWebApp/_layouts/MyProjectName/MyPage.aspx).

This technique has the advantage of being simple to set up, and easy to develop and debug. The minor drawback is that to debug you need to attach to the w3wp processes, and then open the browser with the correct URL in place. This sounds like a small inconvenience, but when repeated hundreds of times a day can become annoying.

 

3. Create a dummy master page

This strategy allows you to develop and debug as you would a normal Web project, with the master page set up to automatically switch when running in the virtual directory environment. The project is set up as a normal Web project, with a dummy master page being created as part of the project. The code for the page is then modified to detect whether it is running in the project directory, or has been deployed and is running in the _layouts folder under the context of a SharePoint site.

The process for setting up a project for this type of development is as follows:

1.       Create a normal Web project

2.       Rename the aspx page to the name of your choice, and modify it to use the correct content placeholder as per the MSDN documentation here.

3.       Add a dummy master page, and set the page content up to mimic the active area’s of the application page as below:

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Application.master.cs" Inherits="MyLayoutPage.Application" %>

<!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" >

<head runat="server">

    <title>Untitled Page</title>

    <asp:ContentPlaceHolder ID="head" runat="server">

    </asp:ContentPlaceHolder>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        <asp:ContentPlaceHolder ID="PlaceHolderPageTitleInTitleArea" runat="server">

        </asp:ContentPlaceHolder>

        <asp:ContentPlaceHolder ID="PlaceHolderPageTitle" runat="server">

        </asp:ContentPlaceHolder>

        <asp:ContentPlaceHolder ID="PlaceHolderMain" runat="server">

        </asp:ContentPlaceHolder>

    </div>

    </form>

</body>

</html>

4.       Set the aspx page to use this dummy master page if the project is being debugged, or to switch to the correct master page if running within the context of a SharePoint site.

a.       Add a private SPWeb object to the class

SPWeb _web = null;

b.      Add an OnPreInit method to switch to the correct master page depending on the context of the page

        protected override void OnPreInit(EventArgs e)

        {

           // Switch the master page if we're running within SharePoint

            if (SPContext.Current != null)

            {

                // Get the local web

                _web = SPContext.Current.Web;  

                string strUrl = "/_layouts/application.master";|

                this.MasterPageFile = strUrl;  

            }

            else

            {

                // Set the master page to our dummy master page, MOSSapplication.master 

                this.MasterPageFile = "MOSSapplication.master";                

                // Get the test web url string

                string sWebTestUrl = ConfigurationManager.AppSettings["TestWebUrl"];  

                // Load the web

                using (SPSite site = new SPSite(sWebTestUrl))

                    _web = site.OpenWeb();

            }  

        }

c.       Add an OnUnload method to clean up the local _web object

        protected override void  OnUnload(EventArgs e)

        {

               base.OnUnload(e);

           

            // Teardown objects if necessary

            if (SPContext.Current == null)

            {

                if (!(_web  == null))

                    _web.Dispose();

            }

        }

d.      Use the _web local object in the project

        protected void Page_Load(object sender, EventArgs e)

        {

            lblSiteTitle.Text = _web.Title;

        }

 

5.       Modify the web.config for the local project, and comment out the line

<authentication mode="Windows"/>

6.       Add the application setting entry in the web.config file to point to the SharePoint web you wish to use for debugging

   <appSettings>

         <add key="TestWebUrl" value="http://MyServer/MySite" />

   </appSettings>

 

This setup allows you to build and debug the project as per normal. When the page is deployed (most often by using a feature in a solution package) into the correct location in the _layouts folder, the page will detect the correct master page and render itself accordingly. When the page is running in the debug folder, it uses the application setting TestWebUrl to bind to the correct web location.

As long as the local _web variable is used throughout the code, the project will automatically use the correct context.

This method has the advantage of being able to use the standard SharePoint master page instead of the application master page, if the page needs to be styled as a normal SharePoint page instead of an admin page. To do this, change the line in the OnPreInit method

string strUrl = "/_layouts/application.master";|

To

string strUrl = _web.MasterUrl;

This will ensure that the correct page is loaded as the master page. (You will need to modify the Content Placeholder tags to be correct for the new master page)

The disadvantage of using this method is that the styles and formatting of the master page are not evident in when debugging, and need to be tweaked and set once the page is deployed. This can be partially mitigated by referencing the correct style sheets (usually /_layouts/1033/styles/core.css) in the dummy master page.

 

At-a-glance

The following table summarizes the methods and their advantages and disadvantages

Method

Advantages

Disadvantages

Best used…

Inline Code

·         Quick and easy to set up

·         Can only be used for the simplest of pages

…for quick, low-risk implementations that display simple data

Copying files

·         Easy to set up

·         Styles show up in development

·         Tedious to debug

…where styling is important or tricky to get right, and only limited repetitive debugging is required

 

 

 

Master page swap

·         Development can be done as normal

·         Master page can be controlled in code

·         More complex to set up

 

 

 

·         Styles and layout cannot be debugged

 

 

 

… where complex code needs to be developed and debugged, and styling can be applied after functionality is complete

 

 

 

 

Other notes

I have glossed over many of the issues that are inherent in application page development. The following are worth a quick note:

Deployment

My preferred method of deploying is to install WSPBuilder from CodePlex, and create feature files in the correct folder hierarchy. This integrates with Visual Studio and provides some handy links for creating and deploying your solution package.

LayoutsPageBase

Most of the code examples use the LayoutsPageBase object as the inherited object for application pages. A normal Page object can also be used, but if it is used the automatic security checks that SharePoint applies will be bypassed, and must be implemented using code in the page

Bin or GAC?

The assemblies can be deployed (and copied in the case of option 2 above) into the bin folder, or deployed into the GAC. It is best practice to use the bin folder, as the assembly will have unrestricted security access if deployed into the GAC. The disadvantage of copying to the correct bin folder when developing is that the dll will only be referenced for the web application into which you copied the assembly.

From the white-paper at http://www.microsoft.com/downloads/details.aspx?FamilyID=65f21935-cbc0-4178-8c08-4c56f721c87d&displaylang=en:

 

Bin

Global assembly cache

Trust level

As specified in web.config file.

Can specify detailed policies.

Grants Full trust to your assembly without affecting the trust level of assemblies installed in the BIN directory.

Scope / availability

Web application (Internet Information Services (IIS) Web site).

Affects the whole physical server.

Strong name

Optional

Required

Requires restart

No

Restart IIS or at least recycle the application pool each time you recompile assemblies.

Tighten security

 

This option is less secure.

Assemblies installed in the global assembly cache are available to all virtual servers and applications on a server running Windows SharePoint Services. This could represent a potential security risk as it potentially grants a higher level of permission to your assembly across a larger scope than is needed.

Licensing

 

Licensing issues may arise due to the global availability of your assembly.

Upgrade from SharePoint 2003

Gradual upgrade does not upgrade items to the new \BIN folder, so you must redeploy your Web Parts.

 

Existence

If a Bin directory does not exist, you must add one. Do not store Web Parts in the _app_bin directory.

Exists

 

Conclusion

Application pages are an extremely useful way of adding user interface interaction to SharePoint applications, that can be accessed from anywhere within the SharePoint farm. The techniques mentioned on this page are methods that I have found are most useful in setting up an application page development project, so that debugging is easiest and deployment is complete.

 

 

peter_reidCAFZC2ME

Peter Reid

SharePoint Consultant

Microsoft Consulting Services UK

Peter.Reid@Microsoft.com

Click here to see my bio