Source included PageReference is used to hold references to pages in the EPiServer system.

Namespace:  EPiServer.Core
Assembly:  EPiServer (in EPiServer.dll) Version: 5.2.375.236

Syntax

C#
[SerializableAttribute]
[TypeConverterAttribute(typeof(PageReferenceConverter))]
public class PageReference : IComparable, 
	IReadOnly<PageReference>, IReadOnly

Remarks

Instead of using raw integer IDs, the ID is packaged in a PageReference structure. A page can have several versions and even be located on another physical server. This information is also stored inside the structure.
CopyC#
#region Copyright � 1997-2008 EPiServer AB. All Rights Reserved.
/*
This code may only be used according to the EPiServer License Agreement.
The use of this code outside the EPiServer environment, in whole or in
parts, is forbidden without prior written permission from EPiServer AB.

EPiServer is a registered trademark of EPiServer AB. For more information 
see http://www.episerver.com/license or request a copy of the EPiServer 
License Agreement by sending an email to info@episerver.com*/

#endregion

using System;
using log4net;
using System.ComponentModel;

namespace EPiServer.Core
{
    /// <summary>
    /// <img src="icons/CSharp.gif" alt="Source included" /> 
    /// <b>PageReference</b> is used to hold references to pages in the EPiServer system.
    /// </summary>
    /// <remarks>
    /// Instead of using raw integer IDs, the ID is packaged in a <b>PageReference</b> structure. 
    /// A page can have several versions and even be located on another physical server. 
    /// This information is also stored inside the structure.
    /// <code source="../EPiServerNET/Core/PageReference.cs" lang="cs"/>
    /// </remarks>
    [Serializable]
    [TypeConverter(typeof(PageReferenceConverter))]
    public class PageReference : IComparable, IReadOnly<PageReference>
    {
        // The ID of a page
        private int _pageID;
        // The version of a page.
        private int _workPageID;
        // A string that identifies a remote site, since introduction of page providers, used to identity the page provider.
        private string _remoteSite;
        // If _anyVersion sets to true then reads will attempt to get published version, and if no published version exists, will fetch the latest version.
        private bool _anyVersion;
        // Indicates if the page is read-only. See IReadOnly for details
        private bool _isReadOnly;
        // Points to the start page.
        private static PageReference _start;
        // Points to the Wastebasket page.
        private static PageReference _waste;
        // Points to the Root page.
        private static PageReference _root;

        /// <summary>
        /// Initializes the <see cref="PageReference"/> class.
        /// </summary>
        static PageReference()
        {
            EmptyReference.MakeReadOnly();
            SelfReference.MakeReadOnly();
        }

        /// <summary>
        /// Returns a <see cref="PageReference"/> that references the current page.
        /// </summary>
        public static readonly PageReference SelfReference = new PageReference(0, -1, null);

        /// <summary>
        /// Returns an empty <see cref="PageReference"/>.
        /// </summary>
        public static readonly PageReference EmptyReference = new PageReference();

        /// <summary>
        /// Gets a <see cref="PageReference"/> to the start page.
        /// <remarks>If start page is not configured, this property returns an empty PageReference.</remarks>
        /// </summary>
        public static PageReference StartPage
        {
            get 
            {
                // We don't need to put lock here becuase in the worst senario we have same result in the _start
                if (_start == null)
                {
                    PageReference tempStart = new PageReference(EPiServer.Configuration.Settings.Instance.PageStartId);
                    tempStart.MakeReadOnly();
                    _start = tempStart;
                }
                return _start;
            }
        }


        /// <summary>
        /// Gets a <see cref="PageReference"/> to the wastebasket page.
        /// </summary>
        public static PageReference WasteBasket
        {
            get
            {
                // We don't need to put lock here becuase in the worst senario we have same result in the _waste
                if (_waste == null)
                {
                    PageReference tempWasteBasket = new PageReference(EPiServer.Configuration.Settings.Instance.PageWastebasketId);
                    tempWasteBasket.MakeReadOnly();
                    _waste = tempWasteBasket;
                }
                return _waste;
            }
        }

        /// <summary>
        /// Gets a <see cref="PageReference"/> to the root page.
        /// </summary>
        /// <value>The root page.</value>
        public static PageReference RootPage
        {
            get
            {
                // We don't need to put lock here becuase in the worst senario we have same result in the _root
                if (_root == null)
                {
                    PageReference tempRoot = new PageReference(EPiServer.Configuration.Settings.Instance.PageRootId);
                    tempRoot.MakeReadOnly();
                    _root = tempRoot;
                }
                return _root;
            }
        }

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="PageReference"/> class.
        /// </summary>
        public PageReference()
        {
        }


        /// <summary>
        /// Initialize a new <see cref="PageReference"/> with page id.
        /// </summary>
        /// <param name="pageID">The Page ID to set</param>
        public PageReference(int pageID)
        {
            _pageID = pageID;
        }

        /// <summary>
        /// Initialize a new <see cref="PageReference"/> with page id and working version.
        /// </summary>
        /// <param name="pageID">The page id to set</param>
        /// <param name="workPageID">The work id to set</param>
        public PageReference(int pageID, int workPageID)
            : this(pageID)
        {
            _workPageID = workPageID;
        }

        /// <summary>
        /// Initialize a new <see cref="PageReference"/> with page id and any available version. If no
        /// version is published the most recently saved will be loaded.
        /// </summary>
        /// <param name="pageID">The page id to set</param>
        /// <param name="anyVersion">This parameter is not used, see remarks</param>
        public PageReference(int pageID, bool anyVersion)
            : this(pageID)
        {
            _anyVersion = anyVersion;
        }

        /// <summary>
        /// Initialize a new <see cref="PageReference"/> with page id and remote site.
        /// </summary>
        /// <param name="pageID">The page id to set</param>
        /// <param name="remoteSite">The name of the remote site</param>
        public PageReference(int pageID, string remoteSite)
            : this(pageID)
        {
            RemoteSite = remoteSite;
        }

        /// <summary>
        /// Initialize a new <see cref="PageReference"/> with page id, working version and remote site.
        /// </summary>
        /// <param name="pageID">The page id to set</param>
        /// <param name="workPageID">The version to set</param>
        /// <param name="remoteSite">The name of the remote site</param>
        public PageReference(int pageID, int workPageID, string remoteSite)
            : this(pageID, workPageID)
        {
            RemoteSite = remoteSite;
        }

        /// <summary>
        /// Initialize a new <see cref="PageReference"/> with page id, working version and remote site.
        /// </summary>
        /// <param name="pageID">The page id to set</param>
        /// <param name="workPageID">The version to set</param>
        /// <param name="remoteSite">The name of the remote site</param>
        /// <param name="anyVersion">This parameter is not used, see remarks</param>
        public PageReference(int pageID, int workPageID, string remoteSite, bool anyVersion)
            : this(pageID, workPageID, remoteSite)
        {
            _anyVersion = anyVersion;
        }

        /// <summary>
        /// Initialize a new <see cref="PageReference"/> from a string in the format
        ///     pageID[_workID[_remoteSite]] or -
        /// throws EPiServerException on invalid argument
        /// </summary>
        /// <param name="complexReference">The string containing page information</param>
        /// <exception cref="EPiServer.Core.EPiServerException">
        /// Thrown if the string cannot be parsed as a valid PageReference.
        /// </exception>
        public PageReference(string complexReference)
        {
            // Invalid argument
            if (String.IsNullOrEmpty(complexReference))
            {
                throw new EPiServerException("PageReference string cannot be null/empty");
            }

            // A bit ugly to allocate a temporary PageReference instance, but the option of duplicating code is worse.
            PageReference temp = Parse(complexReference);
            _pageID = temp._pageID;
            _workPageID = temp._workPageID;
            _remoteSite = temp._remoteSite;
        }

        #endregion

        #region Accessors
        /// <summary>
        /// The id number of a page.
        /// </summary>
        /// <remarks>
        /// The page ID is a database assigned number and the only function is to provide a unique
        /// identification of a page within the current site.
        /// </remarks>
        public int ID
        {
            get { return _pageID; }
            set
            {
                ThrowIfReadOnly();
                _pageID = value;
            }
        }

        /// <summary>
        /// The version id of a page.
        /// </summary>
        /// <remarks>
        /// This is an internal representation of page versions. I e it is not a sequential version
        /// number for a page, but can contain any value. The only guarantee is that if page version A
        /// is created before page version B, then A.WorkID &lt; B.WorkID
        /// </remarks>
        public int WorkID
        {
            get { return _workPageID; }
            set
            {
                ThrowIfReadOnly();
                _workPageID = value;
            }
        }

        /// <summary>
        /// A string that identifies a remote site as defined in the list of remote sites for this installation.
        /// </summary>
        /// <remarks>
        /// To see if the <b>PageReference</b> is a remote link, use the <b>IsRemote()</b> method rather than looking at the
        /// <b>RemoteSite</b>.
        /// </remarks>
        /// <value><b>True</b> if it is a remote reference.</value>
        /// <exception cref="System.NotSupportedException">
        /// Thrown if the instance is read-only.
        /// </exception>
        public string RemoteSite
        {
            get { return _remoteSite; }
            set
            {
                // Thrown NotSupportedException if the page link is read-only
                ThrowIfReadOnly();
                if (String.IsNullOrEmpty(value))
                {
                    _remoteSite = null;
                }
                else
                {
                    _remoteSite = value;
                }
            }
        }
        #endregion

        #region Operators

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <returns>
        /// Returns true if x.ID == y.ID and x.WorkID == y.WorkID and x.RemoteSite == y.RemoteSite
        /// otherwise false
        /// </returns>
        public static bool operator ==(PageReference x, PageReference y)
        {
            // Retuns true if both x and y are equal with null
            if ((object)x == null)
            {
                return (object)y == null;
            }

            // Returns true if (x.ID == y.ID and x.WorkID == y.WorkID and x.RemoteSite == y.RemoteSite)
            return x.Equals(y);
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator !=(PageReference x, PageReference y)
        {
            // Retuns true if only one of them x or y is equal with null
            if ((object)x == null)
            {
                return (object)y != null;
            }
            return !x.Equals(y);
        }

        #endregion

        #region Object overrides

        /// <summary>
        /// Returns true if the objects o is equal with the instance of the PageReference.
        /// </summary>
        /// <param name="o">The o.</param>
        /// <returns></returns>
        public override bool Equals(object o)
        {
            PageReference pageLink = o as PageReference;
            if (o == null)
            {
                return false;
            }
            return _pageID == pageLink.ID && _workPageID == pageLink.WorkID && _remoteSite == pageLink.RemoteSite;
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            return _pageID + _workPageID + (_remoteSite == null ? 0 : _remoteSite.GetHashCode());
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// The return value can be be a string like "Digit[_Digit[_String]]" or "-"
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// The PageReference format can be a string like "Digit[_Digit[_String]]", "-" or String.Empty
        /// </returns>
        public override string ToString()
        {
            if (_pageID == 0)
            {
                // If the page is self reference
                if (_workPageID == -1)
                {
                    return "-";
                }
                else
                {
                    return String.Empty;
                }
            }

            // Convert _pageID to string
            string s = _pageID.ToString();
            // Append the _workID
            if (_workPageID != 0)
            {
                s += "_" + _workPageID.ToString();
            }

            // Append the _remoteSite
            if (_remoteSite != null)
            {
                if (_workPageID == 0)
                {
                    s += "__" + _remoteSite;
                }
                else
                {
                    s += "_" + _remoteSite;
                }
            }

            return s;
        }

        #endregion

        /// <summary>
        /// Compares the instance to the given object.
        /// </summary>
        /// <param name="x">The object to compare against.</param>
        /// <returns>0 if the objects are equal, 1 if this instance is greater than x, -1 if x is greater than this instance.</returns>
        /// <exception cref="System.ArgumentException">
        /// Thrown if x is not of type PageReference.
        /// </exception>
        public int CompareTo(object x)
        {
            // Thrown Exception if the x is not same with the instance
            if (this.GetType() != x.GetType())
            {
                throw new ArgumentException("Object not of the same type");
            }
            // return 0 if x and the instance are equal
            if (this == (PageReference)x)
            {
                return 0;
            }
            //Return 1 if the id of the instance is greater than x
            if (this.ID > ((PageReference)x).ID)
            {
                return 1;
            }
            //Return -1 if the id of the instance is less than x
            return -1;
        }

        /// <summary>
        /// Create a new <see cref="PageReference"/> from a string in the format
        ///     pageID[_workID[_remoteSite]] 
        /// </summary>
        /// <param name="complexReference">The string containing page information.</param>
        /// <param name="result">The PageReference created from the string.</param>
        /// <returns>True if parsing was successful.</returns>
        public static bool TryParse(string complexReference, out PageReference result)
        {
            // Default return value in case of failure
            result = PageReference.EmptyReference;

            // Null or empty is an error
            if (String.IsNullOrEmpty(complexReference))
            {
                return complexReference != null;
            }

            // If "-" then it should be treated as a reference to "self"
            if (complexReference == "-")
            {
                result = PageReference.SelfReference;
                return true;
            }

            // Get the individual components (the full "syntax" of a page reference is <page id>_<work id>_<remote site>)
            string[] components = complexReference.Split('_');
            if (components.Length > 3)
            {
                return false;
            }

            int pageID;
            int workPageID = 0;

            // First component is the page ID - required
            if (!Int32.TryParse(components[0], out pageID))
            {
                return false;
            }
            if (components.Length == 1)
            {
                result = new PageReference(pageID);
                return true;
            }

            // If more than one component, the second is work ID
            if (components[1].Length > 0)
            {
                if (!Int32.TryParse(components[1], out workPageID))
                {
                    return false;
                }
            }

            // If all three components are defined, the final is the remote site
            if (components.Length == 3)
            {
                result = new PageReference(pageID, workPageID, components[2]);
                return true;
            }

            result = new PageReference(pageID, workPageID);
            return true;
        }

        /// <summary>
        /// Parse and return a <see cref="PageReference"/> from a string.
        /// </summary>
        /// <param name="s">The string, in the format  pageID[_workID[_remoteSite]].</param>
        /// <returns>The PageReference, or PageReference.EmptyReference if it's invalid</returns>
        /// <exception cref="EPiServerException">If string is not parsable as a pagereference</exception>
        public static PageReference Parse(string s)
        {
            PageReference pageLink;
            if (!TryParse(s, out pageLink))
            {
                throw new EPiServerException("Invalid PageReference format: " + s);
            }
            return pageLink;
        }

        /// <summary>
        /// Parse a url for <b>PageLink</b>. It is assumed that the url is root-relative,
        /// i.e. starts with a "/".
        /// </summary>
        /// <param name="url">Url to parse, assumed to start with "/"</param>
        /// <returns>A <b>PageReference</b> or <b>PageReference.EmptyReference</b> if it's not a valid reference</returns>
        public static PageReference ParseUrl(string url)
        {
            PageReference pr = PageReference.EmptyReference;
            if (String.IsNullOrEmpty(url))
            {
                return pr;
            }

            // We really expect to begin with "/". This should in the future be a ArgumentException, but this will do for now.
            if (url.StartsWith("//"))
            {
                return pr;
            }

            UrlBuilder urlBuilder = new UrlBuilder(url);
            string id = urlBuilder.QueryCollection["id"];
            if (!String.IsNullOrEmpty(id))
            {
                PageReference.TryParse(id, out pr);
                return pr;
            }

            int indexOfScore = url.IndexOf("____");
            if (indexOfScore > 0)
            {
                // Remove the part after #, if any
                int indexOfAnchor = url.IndexOf("#");
                if (indexOfAnchor > 0)
                {
                    url = url.Substring(0, indexOfAnchor);
                }

                int indexOfDot = url.IndexOf(".", indexOfScore);
                if (indexOfDot > 0)
                {
                    PageReference.TryParse(url.Substring(indexOfScore + 4, indexOfDot - indexOfScore - 4), out pr);
                    return pr;
                }
            }

            return PageReference.EmptyReference;
        }

        /// <summary>
        /// Check if this reference is a remote reference.
        /// </summary>
        /// <returns>True if it is a remote reference.</returns>
        /// <remarks>
        /// A PageReference can point to an external site as indicated by the <see cref="RemoteSite"/> property.
        /// </remarks>
        public bool IsRemote()
        {
            return RemoteSite != null;
        }

        /// <summary>
        /// Check if it is an empty reference.
        /// </summary>
        /// <returns><b>True</b> if it is an empty reference.</returns>
        /// <remarks>
        /// An empty reference is virtually the same as a null value.
        /// </remarks>
        [Obsolete("Use the static method PageReference.IsNullOrEmpty(pageLink) instead.", false)]
        public bool IsEmpty()
        {
            return this == EmptyReference;
        }

        /// <summary>
        /// Determines whether the specified page link is null or empty.
        /// </summary>
        /// <param name="pageLink">The page link.</param>
        /// <returns>
        ///     <c>true</c> if pege link is null or empty; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsNullOrEmpty(PageReference pageLink)
        {
            if (pageLink == null)
            {
                return true;
            }
            return pageLink == EmptyReference;
        }

        [Obsolete("Use the static method PageReference.IsValue(pageLink) instead.", false)]
        public bool IsValue()
        {
            return this != EmptyReference && this != SelfReference;
        }

        /// <summary>
        /// Determines whether the passed <see cref="PageReference"/> is initiated with a value.
        /// </summary>
        /// <param name="pageLink">The <see cref="PageReference"/> object to be checked.</param>
        /// <returns>
        /// <c>true</c> if the passed <see cref="PageReference"/> is not <c>null</c> and does not equal <see cref="PageReference.EmptyReference"/> 
        /// or <see cref="PageReference.SelfReference"/>; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsValue(PageReference pageLink)
        {
            return pageLink != null && pageLink._pageID != 0;
        }

        /// <summary>
        /// Indicates if the <see cref="PageReference"/> references a specific version or may be used to load any available version.
        /// </summary>
        /// <returns>
        /// <c>true</c> if [is any version]; otherwise, <c>false</c>.
        /// </returns>
        /// <remarks>
        /// This method only returns <c>true</c> if the <see cref="PageReference"/> object was created via the <see cref="M:PageReference(System.Int32, System.Boolean)"/> is usually set via the <see cref="M:PageReference(System.Int32, System.Boolean)"/> 
        /// constructor. Typically, that constructor is used when you want to load the latest version a page regardless if it's 
        /// published or not.
        /// 
        /// When a <see cref="PageReference"/> with IsAnyVersion is set to <c>true</c> is passed to <see cref="EPiServer.DataFactory.GetPage"/>
        /// the returned <see cref="PageData"/> object will be, in order of preference:
        /// <list type="number">
        /// <item>The currently published version</item>
        /// <item>The latest saved version</item>
        /// </list>
        ///
        /// If IsAnyVersion is set to <c>true</c>, any value assigned to <see cref="WorkID"/> will be ignored.
        /// </remarks>
        public bool IsAnyVersion()
        {
            return _anyVersion;
        }

        /// <summary>
        /// Compares two PageReferences but ignores WorkID.
        /// </summary>
        /// <param name="pageLink">The PageReference to compare</param>
        /// <returns>Will return <b>true</b> if ID and RemoteSite are the same, otherwise <b>false</b>.</returns>
        public bool CompareToIgnoreWorkID(PageReference pageLink)
        {
            return _pageID == pageLink.ID && _remoteSite == pageLink.RemoteSite;
        }

        /// <summary>
        /// Copies this instance.
        /// </summary>
        /// <returns></returns>
        public PageReference Copy()
        {
            return (PageReference)this.MemberwiseClone();
        }

        #region IReadOnly<PageReference> Members

        /// <summary>
        /// Create a copy of the current object instance that is writable.
        /// </summary>
        /// <returns>A new copy of the object.</returns>
        /// <remarks>
        /// The cloning is a deep-copy.
        /// </remarks>
        public PageReference CreateWritableClone()
        {
            PageReference pageLink = Copy();
            pageLink._isReadOnly = false;
            return pageLink;
        }

        #endregion

        #region IReadOnly Members

        /// <summary>
        /// Changes the <see cref="PageReference"/> into a read-only object.
        /// </summary>
        /// <remarks>
        /// After calling this method, any attempt to modify this instance or any contained object
        /// will generate a <see cref="System.NotSupportedException"/>. I e the semantics is "deep read-only".
        /// <para>
        /// Note! After setting an object to read-only it is not possible to revert back to read-write mode.
        /// You will have to call the CreateWritableClone method to get a copy that can be modified.
        /// </para>
        /// </remarks>
        public void MakeReadOnly()
        {
            _isReadOnly = true;
        }

        /// <summary>
        /// Indicates if the <see cref="PageReference"/> is read-only.
        /// </summary>
        public bool IsReadOnly
        {
            get { return _isReadOnly; }
        }

        #endregion

        /// <summary>
        /// Utility method that, when called, throws a <see cref="System.NotSupportedException"/> indicating that the
        /// <see cref="PageReference"/> has been set as read-only.
        /// </summary>
        /// <remarks>
        /// This method is used internally by other <see cref="PageReference"/> methods to standardize the exception
        /// thrown when trying to modify a <see cref="PageReference"/> set as read-only.
        /// </remarks>
        protected void ThrowIfReadOnly()
        {
            if (IsReadOnly)
            {
                throw new NotSupportedException("The PageReference is read-only.");
            }
        }

    }
}

Inheritance Hierarchy

System..::.Object
  EPiServer.Core..::.PageReference

See Also