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);
}
}
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.
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:
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.
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
Comments
cristian 7 months 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.
Stefan Forsberg 7 months 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".
Joel Abrahamsson 7 months ago
Thanks for your input, it's much appreciated!
And quoting Ayende is always convincing! :)
Ole Jacob Eriksen 7 months ago
I'll say go with number 2.
Kalle Hoppe 7 months 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.
Fredrik Haglund 6 months 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?
Kalle Hoppe 6 months 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.
Joel Abrahamsson 6 months 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.