To initialize a page data object with a custom page provider you have to use a prototype pattern, otherwise will each page read from the database step the page folder once.
(On a CMS 6 version you will override AllocateUniquePageFolderId so it only updates the PageFolderId when a page are created)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using EPiServer;
using EPiServer.Core;
using EPiServer.Web;
namespace Development.PageProvider
{
/// <summary>
/// Page data prototype to initialize page data
/// object without accessing the database.
/// </summary>
public class PageTypePrototype
{
private static Dictionary<string, object> _prototypeCache =
new Dictionary<string, object>();
private static readonly Regex regexFindInvalidUrlChars =
new Regex(@"[^A-Za-z0-9\-_~]", RegexOptions.Compiled);
/// <summary>
/// Locking object for the initialize prototype.
/// </summary>
private static object _initializePrototypeLockObject =
new object();
/// <summary>
/// Initialize a page data object using a prototype so the
/// database isn't called for each fetching of pages from the
/// database.
/// </summary>
/// <param name="pageData">The page data object to initialize.</param>
/// <param name="entity">The entity object to create the PageData bojeck with.</param>
/// <param name="pageLink">The link to the page.</param>
/// <param name="parentLink">Link to the parent page.</param>
public static void InitializePageData(
PageProviderBase adapter,
PageData pageData,
string name,
string pageTypeName,
Guid guid,
PageReference pageLink,
PageReference parentLink)
{
if (!_prototypeCache.ContainsKey(pageTypeName))
{
lock (_initializePrototypeLockObject)
{
if (!_prototypeCache.ContainsKey(pageTypeName))
{
PageData prototype = new PageData();
adapter.InitializePageData(
prototype,
name,
pageTypeName,
guid,
pageLink,
parentLink,
new List<string>());
// This has to be done sense a page access
// can result in a get page
if (!_prototypeCache.ContainsKey(pageTypeName))
{
_prototypeCache.Add(pageTypeName, prototype);
}
}
}
}
PageData initializePrototype =
_prototypeCache[pageTypeName] as PageData;
PropertyDataCollection extraProperties =
pageData.Property.Copy();
pageData.Property.Clear();
for (int i = 0; i < initializePrototype.Property.Count; i++)
{
pageData.Property.Add(initializePrototype.Property[i].Copy());
}
foreach (PropertyData pd in extraProperties)
{
if (pageData.Property[pd.Name] == null)
{
pageData.Property.Add(pd);
}
else
{
pageData.Property[pd.Name] = pd;
}
}
pageData[Const.Property.PageLink] =
pageLink.CreateWritableClone();
pageData[Const.Property.PageParentLink] =
parentLink.CreateWritableClone();
pageData[Const.Property.PageName] = name;
pageData[Const.Property.PageGuid] = guid;
pageData.StartPublish =
EPiServer.BaseLibrary.Context.Current.RequestTime;
pageData.URLSegment = SimpleUrlSegment(name);
UrlBuilder urlBuilder =
new UrlBuilder(initializePrototype.LinkURL);
pageData.LinkURL = ParmanentLink.Create(guid, ".aspx");
foreach (var acl in initializePrototype.ACL)
{
if (!pageData.ACL.Exists(acl.Value.Name))
{
pageData.ACL.Add(acl.Value);
}
}
pageData.ACL.Creator = initializePrototype.ACL.Creator;
pageData.InitializeData(initializePrototype.PageLanguages.ToList());
}
/// <summary>
/// Creates a URLSegment from a page name, without checking if the segment already exists.
/// </summary>
/// <param name="pagename">Page name to create URLSegment for</param>
/// <returns>A (possible) URL Segment for a page.</returns>
public static string SimpleUrlSegment(string pageName)
{
StringBuilder ret = new StringBuilder(pageName);
MatchCollection coll =
regexFindInvalidUrlChars.Matches(pageName);
for (int i = 0; i < coll.Count; i++)
{
object newChar =
UrlSegment.URLCharacterMap[ret[coll[i].Index]];
ret[coll[i].Index] = newChar != null ? (char)newChar : '?';
}
ret.Replace("?", String.Empty);
return ret.ToString();
}
}
}