2

Closed

Initialization fails with custom properties

description

It seems that the PluginAttribute-hack that PageTypeBuilder uses for initialization causes problems with custom properties because of unpredictable initialization order.
 
According to my observations, when searching for plugins to initialize, EPiServer scans assemblies in reverse order by their names. (Although this is probably just coincidental and not specified anywhere.) If PageTypeBuilder is initialized before custom properties, EPiServer has no knowledge of the custom properties and PTB will throw the following exception:
 
[UnmappablePropertyTypeException: Unable to map the type for the property MyProperty in MyPageType to a suitable EPiServer CMS property.]
PageTypeBuilder.Synchronization.Validation.PageTypeDefinitionPropertiesValidator.ValidatePageTypePropertyType(PropertyInfo propertyInfo) +268
PageTypeBuilder.Synchronization.Validation.PageTypeDefinitionPropertiesValidator.ValidatePageTypeProperty(PropertyInfo propertyInfo) +35
PageTypeBuilder.Synchronization.Validation.PageTypeDefinitionPropertiesValidator.ValidatePageTypeProperties(PageTypeDefinition definition) +76
PageTypeBuilder.Synchronization.Validation.PageTypeDefinitionValidator.ValidatePageTypeDefinition(PageTypeDefinition definition, IEnumerable1 allPageTypeDefinitions) +39
PageTypeBuilder.Synchronization.Validation.PageTypeDefinitionValidator.ValidatePageTypeDefinitions(List
1 pageTypeDefinitions) +103
PageTypeBuilder.Synchronization.PageTypeSynchronizer.ValidatePageTypeDefinitions(List`1 pageTypeDefinitions) +19
PageTypeBuilder.Synchronization.PageTypeSynchronizer.SynchronizePageTypes() +40
PageTypeBuilder.Initializer.Start() +127
 
To reproduce, create a new EPiServer solution named "BugTest" with following code:
 
namespace BugTest
{
  [Serializable]
  [PageDefinitionTypePlugIn]
  public class MyCustomProperty : PropertyString
  {
  }
 
  [PageType]
  public class MyPageType : TypedPageData
  {
      [PageTypeProperty(Type = typeof(MyCustomProperty))]
      public virtual string MyProperty { get; set; }
  }
}
 
Note that naming the solution is important: I had some trouble reproducing the bug since at first my test solution was named "PTBTest", which did not produce the bug as it was initialized before PageTypeBuilder.
Closed Apr 18, 2010 at 8:32 PM by joelabrahamsson

comments

joelabrahamsson wrote Feb 5, 2010 at 8:51 AM

Thanks for a great bug report!

I have experienced this problem myself but haven't quite gotten around to fixing it yet. I'll definetly look into it further for the next version.

komu wrote Feb 5, 2010 at 9:28 AM

I worked around the problem by changing the initialization code of PageTypeBuilder a bit. Instead of performing real work in Initializer.Start, I simply register a delegate to be called on InitializationModule.FirstBeginRequest and moved the previous contents of Initializer.Start to this delegate. However, since I'm not familiar with PTB codebase, I don't know if I broke a bunch of other assumptions by this change. At least everything seems to work now.

Anyway, thanks for your work on PageTypeBuilder! I can't imagine developing on EPiServer without it.

komu wrote Feb 5, 2010 at 10:31 AM

Thinking a bit more about this, of course my change would break code that adds callbacks to InitializationModule.FirstBeginRequest during Application_Start and expect them to be called after PageTypeBuilder has initialized itself. So I guess I'll just have to remove Initializer.Start and manually request PageTypeBuilder to initialize itself.

joelabrahamsson wrote Feb 5, 2010 at 11:24 AM

Well, the simple and quick workaround should be to first (before you create a page type with a property of that type) create the custom property, compile and go to the site so that EPiServer will register it. Unless of course this is a different bug then I think?

komu wrote Feb 5, 2010 at 12:03 PM

Yes, that's the workaround we used for some time during development, but of course it's a non-starter when trying to create builds that can be automatically deployed to testing/staging/production environments.

For the time being, we are using a patched version of PageTypeBuilder that does not initialize itself automatically and then call PageTypeBuilder's initialization followed by our own custom initialization (creating basic structure of site etc.) from FirstBeginRequest-hook initialized in Global.asax. On the other hand it's a shame to lose the automagic initialization, but then again things are more explicit now and we have a tighter control over the order of things happening.

JRPatterson wrote Apr 15, 2010 at 4:28 PM

I'm just finding out about this issue now (just started developing with EPiServer) and have found myself that PageTypeBuilder seems to register my custom page types before my custom properties. So what Joel wrote on Feb 5 at 12:24 PM seems to be a way around it, bit of a pain though, how can I 'trick' PageTypeBuilder into finding my custom properties before my custom page type?

This is the only issue I've found myself while working with PageTypeBuilder over the last week. It's an excellent addition EPiServer, hopefully this little issue is solved for the next release.

wrote Apr 15, 2010 at 4:30 PM

joelabrahamsson wrote Apr 18, 2010 at 3:45 PM

It will be fixed in the next version (1.2 Beta 2)

wrote Apr 18, 2010 at 7:15 PM

wrote Apr 18, 2010 at 8:32 PM

komu wrote Apr 19, 2010 at 10:58 AM

Correct me if I am wrong, but I just looked at the change set 40353 which contains the fix and I believe there's still a problem. The committed fix is more or less the same that I proposed in my first comment (dated Feb 5, 12:28 PM), but quickly redacted because it has some problems.

If application itself wants to register a hook on FirstBeginRequest, it will get there before PTB. Since (it seeems that) EPiServer calls the hooks in the order they are registered, this means that at the time that application's FirstBeginRequest-hook will be called PTB has not initialized itself. In our case the whole point of the hook is to create default versions of some basic mandatory pages, but it's not possible since the page types are not created yet.

I understand that the automatic initialization is a nice thing that makes it easy to get started with PTB , but could there be a way to turn it off and do the initialization manually? For us it would be enough it we could do something like:
protected void Application_Start()
{
    PageTypeBuilder.Initializer.AutoInitialization = false;
    InitializationModule.FirstBeginRequest += InitializeApplication;
}

private static void InitializeApplication(object sender, EventArgs e)
{
    PageTypeBuilder.Initializer.Initialize();
    ...
}
As of this moment we are forced to use a patched version of PTB and the unfortunately the current fix would not change that situation. :(

Anyway, thanks again for your work on PTB!

joelabrahamsson wrote Apr 19, 2010 at 1:12 PM

What I had planned to to, but not checked in yet, was to expose a boolean property saying wether PTB has been inialized or not. You could then check this at start up and if it hasn't you can invoke the initialization. That would work for your scenario right?

Also, being able to disable PTB's automatic initialization is definetly interesting, though I would prefer to start with the above approach.

joelabrahamsson wrote Apr 19, 2010 at 1:25 PM

Just did some poking around and it seems the initialization has changed with the introduction of EPiServer.Framework. It now looks simillar to the module system in EPiServer.Common (Community/Mail). I'll probably use that.

komu wrote Apr 19, 2010 at 3:08 PM

Yes, the boolean property and possibility to invoke initialization manually would be good enough. I haven't looked at EPiServer.Framework yet myself, but sounds great if there's now a supported API for initialization.

wrote Feb 14, 2013 at 7:04 PM

wrote May 16, 2013 at 8:34 AM