Breaking Changes in the DataFactory APIs

Introduction

EPiServer CMS 5 supports paging of page listings, starting from the database, in the DataFactory API and in the PageDataSource.

Table of Contents

What is Paging?

Paging is a way to get a subset of information from a larger, ordered list. To be more concrete: If you have a single page node in EPiServer with 5000 child pages (not a recommended way to design your site structure, general recommendation is to limit the number of child pages to less than 1000), and you want to display this list by showing 50 pages at a time the paging API is exactly what you need. You can then request 50 pages starting at index 0, i.e. the first 50 pages and then move on to request 50 pages starting at index 50 etc.

What is the Breaking Change?

There is a complication in the paging APIs caused by the filtering mechanisms, for example filtering based on access rights, causing the request for a specific page.range from the uppermost layer (calling the Select method on the PageDataSource class) not matching the paging parameters when the request reaches the DataFactory API since pages returned from DataFactory may be filtered out. This is handled by PageDataSource continuing to request pages until the requested numer of pages is present.

If the semantics of DataFactory API GetChildren were to remain the same as in EPIServer 4.x (the behavior in EPiServer 4.x is to filter pages based on access rights), we would have to do “paging-to-paging” adaption in DataFactory as well (mismatch between GetChildren and the database layer). This is highly undesirable from a performance standpoint as well as from an architectural perspective. Therefore the decision was made to remove access rights filtering from GetChildren.

How Will this Affect my Code?

If you use the standard EPiServer Web controls (PageList, NewsList etc), you will be unaffected by this change, since we have added an access rights filter to the default filter set used by our controls. The only coding pattern that is affected is if you directly call GetChildren and iterate over the collection to output information.

Code such as this will now give you all pages, regardless of whether the current user has access to those pages or not:

PageReference listingContainer = CurrentPage["RssSource"] as PageReference;

PageDataCollection children = GetChildren(listingContainer);

 

foreach (PageData page in children)

{

    XmlNode item = doc.CreateNode(XmlNodeType.Element, "item", null);

 

    XmlNode itemTitle = doc.CreateElement("title");

    itemTitle.InnerText = page.PageName;

    item.AppendChild(itemTitle);

 

    XmlNode itemLink = doc.CreateElement("link");

    itemLink.InnerText = EPiServer.Configuration.Settings.Instance.SiteUrl +

        page.LinkURL;

   

    item.AppendChild(itemLink);

 

    XmlNode itemDescription = doc.CreateElement("description");

    itemDescription.InnerText = CreatePreviewText(page);

    item.AppendChild(itemDescription);

 

    XmlNode itemCreated = doc.CreateElement("dc",

                "date",

                "http://purl.org/dc/elements/1.1/");

   

    itemCreated.InnerText = page.Changed.ToString("yyyy-MM-ddTHH:mm:sszzz");

    item.AppendChild(itemCreated);

 

    channel.AppendChild(item);

}

To emulate the old behavior, you must add one line of code – the new AccessFilter line shown below:

PageReference listingContainer = CurrentPage["RssSource"] as PageReference;

PageDataCollection children = GetChildren(listingContainer);

new FilterAccess().Filter(children);

There is still a problem that was also present with the old semantics, GetChildren would return unpublished pages if you had sufficient access rights. This was done to support preview in Edit mode, but may be undesirable in many cases. To give you a convenient way to filter out these pages as well, we have created a helper class - FilterForVisitor. Using this class would change the code to look like this:

PageReference listingContainer = CurrentPage["RssSource"] as PageReference;

PageDataCollection children = GetChildren(listingContainer);

FilterForVisitor.Filter(children);