Tuesday, 4 March 2008

NotSupportedException: The property Title is read-only

Few lines of code which are quite self-explanatory and used to be working in pre-EPiServer 5 era.

// get page instance
PageData page = DataFactory.Instance.GetPage(new PageReference(id));

// set new value
"Title"].Value = "here comes some new value!!!";

// save and publish
DataFactory.Instance.Save(page, SaveAction.Publish);

Looks nice and easy ... but there is one problem ... it throws an System.NotSupportedException saying that "The property Title is read-only."

You can use DataFactory.Instance.GetPage() method to load pages but EPiServer 5 will return read-only instance of the page. Compiler will not complain that you are assigning new value to the read-only property but in a runtime you will get the exception. If your goal is to update a page you should use this method to get modifiable instance: PageData.CreateWritableClone()

and it whole should looks like that:

// get read-only page instance
PageData readonlyPage = DataFactory.Instance.GetPage(new PageReference(id));

// get modifiable instance

PageData modifiablePage = readonlyPage.CreateWritableClone();

// set new value
"Title"].Value = "here comes some new value!!!";

// save and publish
DataFactory.Instance.Save(modifiablePage, SaveAction.Publish);

Why EPiServer 5 forces us to write this one extra line of code? Answer is performance! Returning read-only instances is significantly faster and moreover ... in most cases that is what you really need. I guess that in 90% of cases you are accessing data simply to display it for the users. In the rest, 10% cases, you want to update those data. It makes perfect sense to have it working faster in typical cases and to write one additional line of code when you want to modify properties.


cleve said...

Interesting. As a complete novice to Episerver, help me out here, when a page is cached, are all the properties associated with that page read-only as well?

As a developer, I would expect to see a nice convenience method would be not to have to worry about that extra line of code. With that in mind, can I have something like:

UpdateProperty(pageId, propertyName, newValue)

Then inside this method, can I ask the property if it is modifiable (with catching NotSupportedException), for example:


and then this method takes care of all this for me (as well as returning the oldValue from the method :-) ).

Is this possible?

Marek Blotny said...

Hi Cleve, answer is yes, it’s possible.

EPiServer API provides means to get all information which you need. PageData and PropertyData classes have IsReadOnly public property. So when you call DataFactory.Instance.GetPage() metod then returned PageData object will have this property set to true. Of course all properties (PropertyData objects) associated with the page will also have this property set to true.

You can then call PageData.CreateWritableClone() which will return new instance of the same page, but this time the IsReadOnly properties (on PageData and PropertyData objects) will be set to false. And at this point you are free to modify whatever you want.

Hope it answers your question :)

cleve said...

It does. Thanks Marek.

I was just thinking whether such convenience methods come with the framework, or whether at this point in time we build them? Sounds like we have the means to build them.

Dave Bartlett said...

Thank you, this is a fantastic post and has been very helpful.