Why you would deploy custom ASPX pages
SharePoint lets you do a lot out of the box, but as we all know, sometimes the need arises to deploy custom pages within your SharePoint environment. Custom wizards, dashboards, and administration pages are just a few examples where you would like your web pages to exist within SharePoint so that URLs stay consistent, configuration settings can be used, the SharePoint object model can be used, and common security can be leveraged.
Developers do have a few ways that this can be accomplished, each with its own limitations:
Deploy pages under the _layouts directory
This is probably the most common because it’s the easiest to do; this approach is great when you want to quickly deploy several pages that should be exposed to everyone, but things start to get tedious when you want to secure pages (custom code or virtual application), have a more custom tailored set of URLs (always accessible under /_layouts/) or deploy several modules (subdirectories would do the trick, but can get messy).
Create another web application or virtual directory
This approach is also common because you can control security and have independent configuration (i.e. it has its own web.config), but this is also a drawback; it’s tedious to deploy in a repeatable fashion and manage/maintain configurations unless you are planning on supporting a full blown custom application.
Upload pages to a document library using the PageParserPaths section in the web.config
This approach is available, but should be used with great caution. This approach allows users to upload specific aspx pages to a document library and allow the pages to execute. Although you can secure your pages using SharePoint security and you can modularize your pages, any contributor will be able to upload (potentially malicious) aspx pages and as the need for more pages grow, so will the web.config and as we all know changing the web.config is error prone, tedious, and restarts the SharePoint application. For more information on this approach, see: http://msdn.microsoft.com/en-us/library/bb862025.aspx
These are generally the three that are used, but there is ANOTHER way that I find to be very powerful, but much less known…
Use a feature to deploy aspx pages – MY FAVOURITE!!!
I’ve described below how to do this, but let me explain why I like this way so much:
· There is no deployment code: the feature just uses an elements.xml and a feature.xml file, along with your custom aspx pages (and supplementary files: images, JavaScript files, style sheets, etc)
· It’s modular: you can deploy your pages to any document library on any site by activating the feature where you want to deploy the pages (in my example, I’ve made the feature web scoped so that you can deploy the set of pages once on any site or subsite)
· It’s secure: since the pages are in a document library, you can leverage the SharePoint security model, giving everyone who should be able to render the page view rights and strip away all other roles (except for at least one admin who will need to manage security).
· It’s maintainable: Each page’s source is on the file system rather than the database, so even though the pages appear to be in the document library, the content isn’t stored in the content database (this is accomplished using the Type=“GhostableInLibrary” attribute). This is my favourite part about this because it has a lot of extra advantages:
o The page executes fine without having to add PageParserPaths into the web.config (this is because files in the database go through a different page parser than the ones on the file system)
o One source means changes are propagated to where ever the pages may have been deployed. For example, suppose you deployed the same page to multiple sites so that users on those sites could gain the new functionality. If you needed to make a change to that file and the aspx page was added to the content database each time, you would need to change it everywhere where the page was uploaded. This way you make the change in one location on the file system and presto! the changes reflect everywhere
o Only administrators with access to install features can deploy the pages: this reduces the risk of poor or malicious code being introduced into your system. Users that try and upload their own pages through the web interface will end up placing pages into the database which in turn will invoke the database page parser, causing the pages not to execute because there are no entries in the web.config
The one limitation that I’ve come across so far, which I’m still looking for a solution is versioning. Since the pages aren’t stored in the database, if you want to maintain versions of your file, this needs to be done manually.
How to…
Go to the site where you want to deploy your pages
Create the document library that will house the aspx pages

I called mine MiniApp, but you can call it whatever you like. Just make sure the name corresponds to the Url attribute value in the module section of the elements.xml file (more on that below)

MiniApp document library created with no items

Set up your feature
Mine has two custom aspx files, feature.xml, and elements.xml

Inside my feature.xml file
<?xml version="1.0" encoding="utf-8"?>
<Feature Id="34869C66-72B5-4b6b-8928-64F1D85CBD68"
Title="My Mini Application"
Description="Deploy My Mini Application"
Version="12.0.0.0"
Scope="Web"
Hidden="FALSE"
DefaultResourceFile="core"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="elements.xml"/>
</ElementManifests>
</Feature>
Things to note:
· I’ve web scoped this feature so that it can be activated on any site or sub site
· Notice no feature receivers, just a reference to the elements.xml
Inside my elements.xml file
<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="MyMiniAppModule" Url="MiniApp" SetupPath="FEATURES\MyMiniApp" List="101">
<File Url="Home.aspx" Type="GhostableInLibrary" IgnoreIfAlreadyExists="FALSE" />
<File Url="Welcome.aspx" Type="GhostableInLibrary" IgnoreIfAlreadyExists="FALSE" />
</Module>
</Elements>
Things to note:
· The Url attribute in the Module section needs to correspond to the URL of the document library (for example in my elements.xml Url="MiniApp" and my document library URL is http://deathstar:9000/sites/bobsteamsite/MiniApp)
· List="101" represents the document library list type
· The File tags identify all of my custom aspx pages (or any other files you want to deploy)
· The Type value is GhostableInLibrary which tells SharePoint to create an document library item to go with your file on the file system
· SetupPath is the path relative to the TEMPLATE folder (in the 12 hive) where your custom files will be stored on the file system
Inside my Welcome.aspx page
<%@ Page Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Home</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Hello, <% Response.Write(Request.QueryString["user"].ToString()); %>
<br />
<br />
Go back to
<a href="<% Response.Write(Microsoft.SharePoint.SPContext.Current.Site.RootWeb.Url); %>">
<% Response.Write(Microsoft.SharePoint.SPContext.Current.Site.RootWeb.Title); %>
</a>
</div>
</form>
</body>
</html>
Inside my Home.aspx page
<%@ Page Language="C#" %>
<script runat="server">
protected void btnSubmit_Click(object sender, EventArgs e)
{
Response.Redirect("Welcome.aspx?user=" + txtUserName.Text);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Home</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Enter your name: <asp:TextBox ID="txtUserName" runat="server"></asp:TextBox><br />
<asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click" />
</div>
</form>
</body>
</html>
Install your feature

Notice the feature listed on the features page once it is installed

Click activate to deploy the pages

Tada! The pages are now in the MiniApp document library

Start the application
Click on the Home.aspx link to start the application



Clicking on Bob’s Team Site takes me back to the home page

But Wait! There’s a catch!
Readers can still view the source of your aspx pages if they use the “Download a copy” action!

To prevent this, make sure that your assign your users the View Only role instead of the Read role (or create a new group with the View Only role and add your users to it, for example call it “ASPX Viewers”).
The View Only role prevents the option to “Download a copy”.

If you feel comfortable changing permission levels, another way to accomplish this is by creating a new role or modifying an existing role that does not have the “Open Items” permission

That’s it! Happy Custom ASPX Page Deployment!