Strange behaviour with PublishedContentModel and Umbraco.TypedContent
I am using the PublishedContentModel factory for building out this latest site and so far so good and really like how it works but i have come up against a weird behaviour and I'm not sure if its because I'm doing something wrong or there is a bug.
I have manually created my Models (C# Classes) to mirror my document types with inheritance. So for example i have the following doc types:
Base
-- Content
----Homepage
--Repository
----Sliders
--NonContent
----Slide
And my classes (i have skipped the grouping doctypes - i.e no repo class):
Base : PublishedContentModel
Content : Base
Homepage : Content
Slider : Base
Each of those classes call the base(IPublishedContent) constructor.
Now it was all working fine but as i am having the ability to have sliders on every page i have added the slider collections to the Content node.
The content node has a field with slideshow which is a pointer to a slideshow - which contains slides.
So in my content node i am checking the slideshow property and seeing if there is a slideshow set - if there is it goes and builds the collection which is available to the Homepage through inheritance. All fairly straight forward...
Now comes the weird bit.
when i am checking for slideshow the homepage node is: 1065 and the slideshow node 1023.
So i have spun up a UmbracoHelper from the UmbracoContent.Current on the Content class and called:
helper.TypedContent(1023)
The next thing that happens is the PublishedContentFactory (i assume) spawns a new Homepage node - which is not the node passed into the helper. That should be a Slider doc type.
Now is there anything obvious here and have i explained myself?
in a nutshell:
Im on the homepage and check for a slider which gives me the node id of the slider but when i as the helper for TypedContent a new Homepage node is created - which then creates a race condition - leading to a stack overflow if i leave it.
When you do helper.TypedContent(1234) the cache will fetch the internal cache object (here, an XmlPublishedContent) and initialize its structure, therefore initialize its parent. Once the internal object is ready, it is passed to the PublishedContentModelFactory. So when we initialize the parent, same thing happen: fetch the internal cache object, pass it to the factory. That's what you see in your stack trace: at that point the factory is creating a model for the parent node.
That explains why, although 1234 is a slider node, we seem to be spawning a home page node. When you get a node, the xml cache gets all the parents -- the only thing the factory changes is that the parents are models, not plain XmlPublishedContent objects. We walk up the tree to the root. Because the tree does not contain cycles, I fail to see why this would cause a stack overflow or a race condition?
Unless... what exactly are you doing in the constructors? If the constructors trigger the creation of other nodes, then I guess it is possible to create a loop. You want to fetch the value of your SlideShow property later on, not within the ctor.
Thanks for this - as the email notification came in i was just refactoring the class to remove the construction of the slideshow called in the constructor - as per your last point! :)
So i'll finish that up and see if it fixes. I thought it may be building up the tree and walking the path because i use that pattern a lot to find nodes fro the root.
Strange behaviour with PublishedContentModel and Umbraco.TypedContent
I am using the PublishedContentModel factory for building out this latest site and so far so good and really like how it works but i have come up against a weird behaviour and I'm not sure if its because I'm doing something wrong or there is a bug.
I have manually created my Models (C# Classes) to mirror my document types with inheritance. So for example i have the following doc types:
Base -- Content ----Homepage --Repository ----Sliders --NonContent ----Slide
And my classes (i have skipped the grouping doctypes - i.e no repo class):
Base : PublishedContentModel Content : Base Homepage : Content Slider : Base
Each of those classes call the base(IPublishedContent) constructor.
Now it was all working fine but as i am having the ability to have sliders on every page i have added the slider collections to the Content node.
The content node has a field with slideshow which is a pointer to a slideshow - which contains slides.
So in my content node i am checking the slideshow property and seeing if there is a slideshow set - if there is it goes and builds the collection which is available to the Homepage through inheritance. All fairly straight forward...
Now comes the weird bit.
when i am checking for slideshow the homepage node is: 1065 and the slideshow node 1023.
So i have spun up a UmbracoHelper from the UmbracoContent.Current on the Content class and called:
helper.TypedContent(1023)
The next thing that happens is the PublishedContentFactory (i assume) spawns a new Homepage node - which is not the node passed into the helper. That should be a Slider doc type.
Now is there anything obvious here and have i explained myself?
in a nutshell:
Im on the homepage and check for a slider which gives me the node id of the slider but when i as the helper for TypedContent a new Homepage node is created - which then creates a race condition - leading to a stack overflow if i leave it.
Here is the call stack after i call TypedContent(1023)
Just to add i have just tried to use the UmbracoHelper from a view to get an alternative page and again the Homepage is created.
I wonder if there is some code in the TypedContent that gets the root document (AnscestorOrSelf(1) and that is creating a homepage? Will go look...
May just have to rethink what i put in the Models...
When you do helper.TypedContent(1234) the cache will fetch the internal cache object (here, an XmlPublishedContent) and initialize its structure, therefore initialize its parent. Once the internal object is ready, it is passed to the PublishedContentModelFactory. So when we initialize the parent, same thing happen: fetch the internal cache object, pass it to the factory. That's what you see in your stack trace: at that point the factory is creating a model for the parent node.
That explains why, although 1234 is a slider node, we seem to be spawning a home page node. When you get a node, the xml cache gets all the parents -- the only thing the factory changes is that the parents are models, not plain XmlPublishedContent objects. We walk up the tree to the root. Because the tree does not contain cycles, I fail to see why this would cause a stack overflow or a race condition?
Unless... what exactly are you doing in the constructors? If the constructors trigger the creation of other nodes, then I guess it is possible to create a loop. You want to fetch the value of your SlideShow property later on, not within the ctor.
Making sense?
Hi Stephan,
Thanks for this - as the email notification came in i was just refactoring the class to remove the construction of the slideshow called in the constructor - as per your last point! :)
So i'll finish that up and see if it fixes. I thought it may be building up the tree and walking the path because i use that pattern a lot to find nodes fro the root.
Will update let you know how it goes.
Yep
Removing creation of objects from the contractor worked. They get retrieved now when the property is accessed.
Really like how this works and helping get all that logic out of the views! :)
Thanks Damian
is working on a reply...