PropertyLinkCollection and the introduction of IPermanentLinkMapper in CMS 6 R2

Background

After upgrading a site from CMS 6 R1 to CMS 6 R2 a custom property started to throw null reference exceptions. The custom property inherited from PropertyLinkCollection and according to the stack trace the null reference exception happened somewhere in the GetMappedHref method of the LinkItem class. After scratching my head a bit and looking at various things, for instance if the format of a LinkItem was changed between R1 and R2 (it’s not), I fired up reflector ILSpy.

I compared the GetMappedHref between 6.1.379.0 and 6.0.530.0 and a change regarding how the links are mapped caught my eye.

// In 6.1.379.0
if (this._linkMapper.TryToMapped(this.Href, out url))

// In 6.0.530.0
if (PermanentLinkMapStore.TryToMapped(this.Href, out url))

The member _linkMapper is of type IPermanentLinkMapper and is a new abstraction introduced in R2.

Our usage of PropertyLinkCollection

As I mentioned we’re using a custom property that inherits from PropertyLinkCollection. The constructor to our custom property looks like the following

public PropertyLinkCollectionEx()
    : base(new LinkItemCollectionEx())
{
}

Basically we’re using the ctor overload that takes a LinkItemCollection, in which we’re passing another custom property that inherits from LinkItemCollection. If we compare the constructors available from PropertyLinkCollection between R1 and R2 we find the following:

// In 6.1.379.0
PropertyLinkCollection()
PropertyLinkCollection(IPermanentLinkMapper linkMapper)
PropertyLinkCollection(LinkItemCollection linkItemCollection)

// In 6.0.530.0
PropertyLinkCollection()
PropertyLinkCollection(LinkItemCollection linkItemCollection)

It became quite obvious that since we’re not using an overload that specifies an IPermanentLinkMapper it results in a null reference exception when it’s used in the LinkItem class. If you look at the default PropertyLinkCollection constructor in R2 it looks like this:

public PropertyLinkCollection()
{
	this._linkItemCollection = new LinkItemCollection();
	this._linkMapper = new PermanentLinkMapper();
}

After constructor, construction should be done

As you noticed we have a need to pass a LinkItemCollection to out base class since we’re using our own implementation. This poses a problem since we need to use this overload and also specify which implementation of IPermanentLinkMapper to use and there isn’t an overload that takes both of these. The somewhat hackish solution I ended up with is using the overload that takes an IPermanentLinkMapper and then set the Links property.

public PropertyLinkCollectionEx()
    : base(new PermanentLinkMapper())
{
    Links = new LinkItemCollectionEx();
}

However, if there isn’t anything I’ve completely missed (it wouldn’t be the first time), I do feel that after calling the constructor the object should be in a valid state. There probably should be an overload that takes both a LinkItemCollection and IPermanentLinkMapper or set it to some sort of default implementation in the ctor that takes a LinkItemCollection. Or maybe just use an IoC-container and real dependency injection.

  • http://twitter.com/paulsmith_epi Paul Smith

    This has been reported as a bug in CMS 6 R2 (#64852)