Changing namespace of block results in error

Vote:
 

Today I ran into a weird issue when refactoring code. As a result of the refactoring I changed the namespace of a block contenttype. 

This resulted in a runtime error when synchronizing the contenttypes:

ContentType with name '{0}' has a ModelType '{1}' that does not correspond to the required 'IContent'.

Which is a rather strange error because blocks do not implement IContent (at least not at compile time).

After decompiling the code responsible for generating the error: EPiServer.DataAbstraction.Internal.DefaultContentTypeRepository, I found out that the error originated from the following code in the ValidateModelType method:

 else
      {
        this._circularReferenceValidator.Analyze<ContentData>(type3);
        Type type4 = this._contentTypeBaseResolver.Resolve(contentType.Base);
        if ((object) type4 != null)
        {
          if (!type4.IsAssignableFrom(type3))
            throw new InvalidModelTypeException(type3, string.Format("ContentType with name '{0}' has a ModelType '{1}' that does not correspond to the required '{2}'.", (object) contentType.Name, (object) type3, (object) type4.Name));
        }
        else if (!typeof (IContent).IsAssignableFrom(type3))
          throw new InvalidModelTypeException(type3, string.Format("ContentType with name '{0}' has a ModelType '{1}' that does not correspond to the required '{2}'.", (object) contentType.Name, (object) type3, (object) "IContent"));
      }

The line with:

Type type4 = this._contentTypeBaseResolver.Resolve(contentType.Base);

Is using a "Base" property on the contenttype. When checking our database I saw that the column "Base" in table "[dbo].[tblContentType]" was filled with values for all Episerver contenttypes, but our project specific contenttypes all had a NULL value.

After filling the column "Base" with value "Block" for our custom blocks things started working again.

I am not sure why this error occured, it feels like an issue with an Episerver upgrade. The column was recently added after upgrading to a new Eiserver version I think (it isn't there in my current version of the Episerver Foundation project).

The comments on the Base property of the ContentType class is:

/// <summary>
/// NOTE: This is a pre-release API that is UNSTABLE and might not satisfy the compatibility requirements as denoted by its associated normal version.
/// Gets or sets the base for this content type instance (e.g. page or block or etc).
/// </summary>

:)

We are currently on version EPiServer.Framework 11.15.1.

Can someone tell me why this is happening?

#223947
Jun 08, 2020 9:12
Vote:
 

Strange. Did you have a GUID specified in your ContentType attribute for that block?

#223949
Jun 08, 2020 9:48
Vote:
 

Yes, I forgot to mention that. Definitely using GUIDs :).

#223950
Jun 08, 2020 9:49
Vote:
 

And another extra observation: for new contenttypes the "Base" column gets a value when the contenttype is added to the DB.
So, it looks like some migration went wrong.

#223954
Jun 08, 2020 11:02
Vote:
 

I ran into the same problem when refactoring and changing the namespace of a block.

After filling in "Block" in the (local) database in the "base" field in the row in tblContentType the problem was fixed and the site loaded again.

I have no access to the databases in our INT, PRED and PROD environments, so a fix for this problem would be welcome.

#224056
Jun 10, 2020 8:54
Vote:
 

This problem occurred in version 11.15.1 and is not fixed in the latest 11.16.0 version. Best thing is to roll back to version 11.15.0.

EPiServer support is aware of this problem and a fix in the CMS.Core package will probably be released in version 11.17.0

#224058
Edited, Jun 10, 2020 9:51
Henk - Jul 24, 2020 6:33
Looks like the issue is fixed in CMS.Core 11.17.0.
Vote:
 

I encountered the same problem in DXC. I used EF migrations on our DB context to manually run SQL statements to update the ModelType. The trick was how to get the migrations to run before the ModelSyncInitialization so I could make it work on DXC. In the end I figured out I could (mis)use the IConfigurableModule interface for a database initialization module as the ConfigureContainer method is run on all modules before initialization begins.

    [InitializableModule]
    public class DatabaseInitialization : IConfigurableModule
    {
        public void ConfigureContainer(ServiceConfigurationContext context)
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, MyDbConfiguration>());
            using (var db = new MyDbContext())
            {
                db.Database.Initialize(false);
            }
        }

        public void Initialize(InitializationEngine context) { }

        public void Uninitialize(InitializationEngine context) { }
    }
    public partial class DatabaseFixes : DbMigration
    {
        public override void Up()
        {
            Sql("update [tblContentType] set ModelType = 'MyProject.Models.Blocks.MyBlock, MyProject.NewProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' where ModelType = 'MyProject.Models.Blocks.MyBlock, MyProject.OldProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'");
        }

        public override void Down()
        {
        }
    }
#224071
Jun 10, 2020 15:20
Vote:
 

I should add in my case as you can see I didn't get to the stage of playing with the base field - just updated the ModelType to match my refactoring - but the same approach should be useable for any database script you need to run before model synchronisation.

#224072
Jun 10, 2020 15:31
Vote:
 

@Mark: I think you could use an Episerver MigrationStep for this .. I tried to use this to update the Base property on a contenttype, but this fails because of checks in the internal Episerver code.

So, going around this using EF migrations in an Episerver MigrationStep could make sure this is ran before ModelSyncInitialization.

#224103
Jun 11, 2020 6:21
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.