Monday, 16 February 2009

EPiServer - Outgoing Links

In this post I will show how to get list of all referenced pages (and files) for any EPiServer page. Although it sounds like a trivial task, in fact, it's not so obvious. First of all it's necessary to realize that there are two major groups of "linking" properties:
  • Properties that derive from PropertyPageReference, internally they store link as a page id. Out of the box there in only one property type in EPiServer which uses this class -- PageReference.
  • And the bunch of properties which use permanent links internally like:
    • PropertyImageUrl - Url to image
    • PropertyDocumentUrl - Url to document
    • PropertyUrl - URL to page/external address
    • PropertyXhtmlString - Xhtml Long String
    • PropertyLinkCollection - Link Collection
It's fairly simple to get referenced page from PropertyPageReference:

   1:  var pageReference = CurrentPage.Property["propert_name"] as PropertyPageReference;
   2:  var page = DataFactory.Instance.GetPage(pageReference.PageLink);

What about other property types? There is a one common thing for them -- they all implement IReferenceMap interface:


We can use following code to get outgoing links:

   1:  var referenceMap = property as IReferenceMap;
   2:  if (referenceMap != null)
   3:  {
   4:      IList<Guid> linkIds = referenceMap.ReferencedPermanentLinkIds;
   5:      foreach (Guid guid in linkIds)
   6:      {
   7:          PermanentLinkMap map = PermanentLinkMapStore.Find(guid);
   8:          
   9:          // mappedUrl example: /Templates/Public/Pages/NewsItem.aspx?id=30
  10:          string mappedUrl = map.MappedUrl.ToString();
  11:  
  12:          // and get friendly URL version using UrlRewriteProvider
  13:          var url = new UrlBuilder(mappedUrl);
  14:          EPiServer.Global.UrlRewriteProvider.ConvertToExternal(url, null, System.Text.Encoding.UTF8);
  15:          string friendlyUrl = UriSupport.AbsoluteUrlBySettings(url.ToString());
  16:      }
  17:  }

What are permanent links?

Internal URL's in EPiServer are stored in the database using a format called Permanent Links. Property types are responsible to transform a URL from a permanent link to a standard template link upon access from user code, and of course the other way around before content is stored to the database.
It's a very useful feature of EPiServer because it enables you to manipulate files and pages without risk that some links will get broken.
You can rename files and templates without affecting the links; you can even move an EPiServer site from a virtual directory to a root site without breaking a single link.

Permanent Links and EPiserver's API

IReferenceMap Interface exposes ReferencedPermanentLinkIds property thanks to which we have access to all links stored internally. That is very convenient especially for properties like PropertyXhtmlString which usually also store lots of other data. It is worth noticing that PropertyLongString doesn't implement this interface, hence it doesn't use permanent links. That is a reason why PropertyXhtmlString is recommended over PropertyLongString.

PermanentLinkMapStore class is a part of EPiServer's API for permanent links. I used this class to get mapped URL based on link's Guid. In next step mapped URL can be converted to friendly URL (code based on Ted Nyberg's post). Permanent link can be broken (referenced page was deleted) in which case PermanentLinkStore.Find() method will return null.

Based on above code I have created an edit mode plugin which lists all outgoing links, it looks like this:

Source code can be downloaded from here.

Other interesting posts:

6 comments:

Mirek said...

Hi,
Very nice article. And for your record, below is a code fragment to find incoming links which may, in some cases, be also useful.

DataSet referingData = new PageSaveDB().DeleteCheck(CurrentPage.PageLink);
foreach (DataRow row in referingData.Tables[0].Rows)
{
int referenceType = Convert.ToInt32(row["ReferenceType"]);
int pageId = Convert.ToInt32(row["pkid"]);

// do something
}

cheers,

Marek Blotny said...

Hi Mirek, thanks for your comment, great input!

blog said...

Hi Marek!

Perfect timing! I had this in my research backlog so you saved me some work.

Do you also check if the outgoing link is to something in the waste basket?

/Fredrik

Marek Blotny said...

Hi Fredrik, yes, the above approach will also find links to pages in the waste basket.

Your blog saved me a lot of work as well so I guess we say that we are even ;)

Dave said...
This comment has been removed by the author.
Dave said...

Thanks everyone - this post and comments have put me on the right track.