Ghosted and Unghosted Pages
Introduction
Each .aspx page is rendered by one of two possible parsers. When a request is received for an .aspx page, the SharePoint isapi filter determines who will handle the rendering of the page—Asp.net or the SharePoint SafeMode parser. The first parser, Asp.net, requires the least amount of introduction. The second parser is unique to Windows SharePoint Services.
The intent of this document is to cover the differences between the two parsers. To be very clear, this document applies to pages that come from the main application root of a SharePoint virtual server. Pages which originate from either the “_layouts” or “_vti_bin” virtual directories can be excluded from the discussion.
All pages within SharePoint are stored in the database. This effectively means that, for each document, you will find a row in the docs table for that document. The actual file is stored in the Content column. This is true for all files. However, there is one exception—some .aspx pages don’t actually have their content stored in the database. Instead, these pages reference files that exist on the server’s file system. These pages are considered ghosted pages.
From a technical standpoint, ghosted pages are those rows in the docs table that have null values for the Content column and a non-null value for the SetupPath column that points to a file on the file system itself. The referenced file essentially serves as a template and content source.
What pages are ghosted? For example, the default home page is a ghosted page. Any Web part pages created by the New Web Part Page user interface are also ghosted.
As you can see, I’ve described ghosted pages as the exception to the rule. What does it mean if a document doesn’t reference a template on the file system? Or, more to the point, what if the Content column actually contains data? These pages are known as unghosted .aspx pages and they are routed through the SafeMode parser.
What is the Main Difference Between the SafeMode Parser and Asp.Net?
During code compilation, Asp.net will parse a page on first render and compile it into an assembly. The SafeMode parser does NOT compile pages. It is designed to interpretatively parse a page and create the object structure of the page. In the event that inline server-side code is detected, the SafeMode parser will not allow the page to render. Additionally, the only objects within the page (for example, controls marked as runat=server) that can be instantiated are those items found in the SafeControls list.
Can a Page Transition from a Ghosted State to Unghosted?
Yes, ghosted pages become unghosted once a file has been modified. If a page is updated by using FrontPage 2003, Web folders, or the modification of custom document library fields, the Content column of the given document row is populated with the page contents. All uploaded .aspx files are automatically unghosted.
Are There Other Differences Between SafeMode and Asp.Net?
Yes. Although the SafeMode parser was designed to be serve as a replacement for the Asp.net parser, it does not offer identical functionality. The key differences between the two parsers are listed below:
- SafeMode does not offer AspCompat functionality.
- SafeMode does not compile; therefore, all compilation directives are ignored.
- Session State exists; however, in SafeMode once you turn it on, all unghosted pages are forced to participate in Session State. Unghosted pages do NOT have the option to opt out of using State.
Why Are There Two Types of Rendering Engines?
They exist for security and scalability. The SafeMode parser ensures that unghosted pages are not allowed to run code. This security feature prevents a user from injecting code into page that may maliciously, or unintentionally, bring down a server, snoop data, and so forth. Consider the permission levels associated with updating a page versus the number of users within a WSS server—if you’re the admin, you would probably be extremely wary of giving anyone the “Add and Customize Pages” right, knowing that they would be able to freely execute server-side code if the SafeMode parser didn’t exist. With your current behavior, once a page is transitioned from a ghosted to unghosted state, the admin knows that page cannot influence the behavior of the server.
Additionally, without the SafeMode parser, all pages would have to be routed through Asp.net, which would mean that all pages would be compiled and their associated assembly loaded into memory. Imagine a site with thousands of operational pages… the memory requirement would be huge. The current design limits page compilation to a very small number of pages relative to the actual number of pages within a WSS-extended virtual server.
How Can We Determine Whether a Given Page Is Either Ghosted or Unghosted?
There is a single property that will tell us: “vti_hasdefaultcontent.” If this property exists on a file, it is ghosted (again, on the filesystem). If the property does not exist, the file is being served from the database.
Here’s the code for a simple command-line utility that will take the URL to a given page and report whether it is ghosted or unghosted:
===== using System; using Microsoft.SharePoint; namespace GhostCheck { public class Checker { [STAThread] static void Main(string[] args) { //if vti_hasdefaultocontent = true, it is ghosted; //if unghosted, the prop doesn't exist if(args.Length == 0 || args[0].ToString().Equals("/?")) { Help(); } else { string sURL = args[0].ToString(); bool hasError = false; string sGhosted = CheckGhost(sURL, out hasError); if(hasError) { Console.WriteLine("nError encountered: {0}", sGhosted); } else { Console.WriteLine("nThe page at {0} is {1}", sURL, sGhosted); } } } static void Help() { Console.WriteLine("nghostcheck <URL>"); Console.WriteLine("nExample: ghostcheck http://<myserver>/sites/<site>/Lists/Contacts/NewForm.aspx); } static string CheckGhost(string FileURL, out bool ErrorFlag) { ErrorFlag = false; SPSite oSite = null; SPWeb oWeb = null; SPFile oFile = null; try { oSite = new SPSite(FileURL); } catch(System.Exception exSite) { ErrorFlag = true; return String.Format("Error getting Site: {0}", exSite.Message); } try { oWeb = oSite.OpenWeb(); } catch(System.Exception exWeb) { ErrorFlag = true; return String.Format("Error getting Web: {0}", exWeb.Message); } try { oFile = oWeb.GetFile(FileURL); } catch(System.Exception exFile) { ErrorFlag = true; return String.Format("Error getting File: {0}", exFile.Message); } System.Collections.Hashtable oHash = oFile.Properties; if(oHash.ContainsKey("vti_hasdefaultcontent")) { return "ghosted (on file system)"; } else { return "unghosted (in database)"; } } } }
Is It Possible to “Reset” an Unghosted Page to Its Original Ghosted State?
No. This ties into the previous answer. Straight out of the box, there is no way to return a page to its original ghosted state.
Help. I Need to Reset a Page!! Surely There Are Options?!
Check out the GhostHunter Web Part that is included in the Web Part Toolkit. The GhostHunter Web Part was specifically designed to address the limitations of WSS with respect to ghosted and unghosted pages.