A common problem with Page Type Builder and UniqueValuePerLanguage set to false

I’ve gotten quite a few questions lately regarding a problem where (code) properties that have the UniqueValuePerLanguage property in the PageTypeProperty attribute has been set to false returns null for pages that are in a different language than the master language. Although I understand the confusion this is actually by design, although I’m starting to have some doubts whether that decision was correct.

I’ll give some background on this issue shortly, but if you’re eager for a solution let me first tell you that it’s to implement your property like this:

[PageTypeProperty(UniqueValuePerLanguage = false)]
public string MyProperty
{
    get
    {
        returh this.GetPropertyValue(page => page.MyProperty, true);
    }
}

Background

EPiServer has two ways of fetching the value of a property. One is through the the Item/string indexer property or the Property property, like this:

object value = pageData["propertyName"];
//or like this
object value = pageData.Property["propertyName"].Value;

The other is by using the PageData.GetValue() method, like this:

object value = pageData.GetValue("propertyName");

There is an important difference between these two methods of retrieving property values. The first one will return the value of a property with the specified name in the PageData objects own PropertyDataCollection OR from a property returned from a GetPropertyDelegate. The second method, GetValue(), on the other hand will only return the value of a property from the PageData objects own collection of properties.

That is, using GetValue() will return values that are guaranteed to come from a property on the PageData object itself. The first method, using the string indexer or Property property on the other hand will first look for a property with a value on the PageData object itself but then also try to find a property with a value using a GetPropertyDelegate. As default this delegate is a method that will check for a value in three ways. It will first check if the requested property isn’t language specific and if the value exists in the master language. Then it will check if the page is of the “fetch data from” type and if so return a value from the page it’s supposed to fetch data from. Thirdly, it will try to return a value from a dynamic property with the same name.

As you might have guessed doing everything that the default GetPropertyDelegate does isn’t free of charge performance wise. Therefore I usually try to use GetValue() and only use the string indexer when I know I need to. This is also one of the reasons why I decided to implement the GetPropertyValue() method in Page Type Builder so that it uses GetValue(). That’s also how automatic properties (get; set;) are implemented. There is however an overload to GetPropertyValue() that accepts a Boolean argument with which you can specify if a GetPropertyDelegate should be used or not.

Possible future changes to this behavior

While I think it’s good to encourage people to stay away from dynamic properties (and PTB offers an alternative) this is by far the most common question that I’ve gotten regarding Page Type Builder except “how’s the performance” (good by the way :-)). I think the reason for this is that people are used to using the string indexer to fetch property values and therefore the standard behavior in PTB differs from EPiServer’s standard behavior. With that said, I’m not sure what’s the best way to solve this.

I see a number of possible ways to tackle this in version 1.2:

  1. Keeping the current implementation. This means that PTB’s standard implementation will be the one that has the best performance but developers of multilingual sites will have to actively consider how they implement their properties.
  2. Changing it so that GetPropertyValue() and automatic properties (get; set;) will use GetPropertyDelegates as default. This will probably be perceived as more “EPi-standard” but will add unnecessary overhead for properties that don’t need it.
  3. One of the above as standard but an option to change it to the other at startup (or in the application configuration, but I think this is a detail that is best configured in code).
  4. Either alternative one or two but with the ability to change it for each property in the PageTypeProperty attribute (via a property such as “UseGetPropertyDelegates = true/false).

Any well motivated opinions or other input on this is much welcome!

PS. For updates about new posts, sites I find useful and the occasional rant you can follow me on Twitter. You are also most welcome to subscribe to the RSS-feed.

Comments

  1. cristian's avatar

    cristian 2 years ago

    I'd go for the "slower" approach (2.) by default and make the "property value getter method" injectable/configurable.

    If you made initialization explicit this could be an option you can configure as you initialize.

  2. Stefan Forsberg's avatar

    Stefan Forsberg 2 years ago

    I agree with Cristian.

    The string indexer is more of a standard approach, I think the templates that comes with EPi uses that method for instance. Although I definitely see your points about performance I'm not sure that a library such as PTB is the best way to educate developers about the EPi-framework and/or API.

    To quote Ayende@Rahien, "When the design violates the principle of least surprise, you don’t close it as By Design".

  3. Joel Abrahamsson's avatar

    Joel Abrahamsson 2 years ago

    Thanks for your input, it's much appreciated!
    And quoting Ayende is always convincing! :)

  4. Ole Jacob Eriksen's avatar

    Ole Jacob Eriksen 2 years ago

    I'll say go with number 2.

  5. Kalle Hoppe's avatar

    Kalle Hoppe 2 years ago

    It would be nice if it could be configurable by say setting a property in a base class, a class atribute maby. In this way yuou could then coose the default behaviure.
    The drawback of this is as a new dev. how to know which setting is the default has been used as default.

  6. Fredrik Haglund's avatar

    Fredrik Haglund 2 years ago

    I vote for number 2.

    My arguments are that this is the expected behavior in EPiServer CMS, the built-in properties on PageData are using the default indexer too and finally that I have a gut feeling that GetPropertyDelegate does not add much overhead compared to everything else going on to handle a request...

    Do you have any measurements on the performance difference?

  7. Kalle Hoppe's avatar

    Kalle Hoppe 2 years ago

    Jepp,No 2. expected behavior is the way to go, and as Fredrik said, without measurements it's just a hypothesis. Sure it will have a slightly higher cost but it's quite annoying to have to remember to set that true flag every now and then.

  8. Joel Abrahamsson's avatar

    Joel Abrahamsson 2 years ago

    Fredrik, no, I haven't measured it, but as you say, compared to other things it's probably not that big of a deal.

  9. Linus's avatar

    Linus 4 months ago

    1 up for behaviour being as close as expected as possible!

Follow me on Twitter

  1. @unclebobmartin Because code coverage is a number that management can measure? 13 hours ago
  2. I'm amazed. "oikeinkirjoitusehdotuksista" is an actual word in the Finnish language! 13 hours ago
  3. @tednyberg Amen to that! 14 hours ago
follow me

Latest comments

  1. Per Ivansson wrote "We will definitely try to release as continiously as we poss..." on On selling 200OK and Truffler to EPiServer
  2. Joel Abrahamsson wrote "Thanks Andreas! Regarding your questions it's not really ..." on On selling 200OK and Truffler to EPiServer
  3. Andreas R wrote "Congrats on the sale. Hope ur rolling around in cash now ;) ..." on On selling 200OK and Truffler to EPiServer

About this site

This blog is built with EPiServer Community, EPiServer CMS, ASP.NET MVC and a bunch of other great products. The source code is available for download at the projects page, where you also can read more about this site and my other projects.

read more