November Happy Hour will be moved to Thursday December 5th.

EPiServer.Forms 5.9.1 Upgrade Initialization crashes - UpdateMissingUploadFolderACL + Workaround

Vote:
 

I saw there was already a reported post about this initialization module but I think the problem I got is slightly different. This other report is found here: https://world.optimizely.com/forum/developer-forum/Problems-and-bugs/Thread-Container/2024/8/episerver-forms-5-7-2-and-newer-crashes-on-initialization/

My stacktrace was:

2024-08-22T16:24:29.3623032Z	fail: EPiServer.Framework.Initialization.InitializationEngine[0]
2024-08-22T16:24:29.3624047Z	      Initialize action failed for 'Initialize on class EPiServer.Forms.EditView.InitializationModule, EPiServer.Forms.UI, Version=5.9.1.0, Culture=neutral, PublicKeyToken=8fe83dea738b45b7'
2024-08-22T16:24:29.3624251Z	      EPiServer.Core.ContentNotFoundException: Content with Guid "cb9f817f-139b-4db7-957f-d84ad527d3bc" was not found
2024-08-22T16:24:29.3624371Z	         at EPiServer.Core.Internal.DefaultContentLoader.Get[T](Guid contentGuid, LoaderOptions loaderOptions)
2024-08-22T16:24:29.3624454Z	         at EPiServer.Core.Internal.DefaultContentLoader.Get[T](Guid contentGuid)
2024-08-22T16:24:29.3624589Z	         at EPiServer.Core.Internal.DefaultContentRepository.Get[T](Guid contentGuid)
2024-08-22T16:24:29.3624671Z	         at EPiServer.Forms.EditView.Internal.MigrationService.UpdateMissingUploadFolderACL()
2024-08-22T16:24:29.3624754Z	         at EPiServer.Forms.EditView.JobScheduler.UpdateUploadFolderACLJob.Execute()
2024-08-22T16:24:29.3624855Z	         at EPiServer.Forms.EditView.InitializationModule.TryExecuteUpdateFolderACLJob()
2024-08-22T16:24:29.3624936Z	         at EPiServer.Forms.EditView.InitializationModule.Initialize(InitializationEngine context)
2024-08-22T16:24:29.3625028Z	         at EPiServer.Framework.Initialization.Internal.ModuleNode.<>c__DisplayClass4_0.<Initialize>b__0()
2024-08-22T16:24:29.3625137Z	         at EPiServer.Framework.Initialization.Internal.ModuleNode.Execute(Action a, String key)
2024-08-22T16:24:29.3625219Z	         at EPiServer.Framework.Initialization.Internal.ModuleNode.Initialize(InitializationEngine context)
2024-08-22T16:24:29.3625332Z	         at EPiServer.Framework.Initialization.InitializationEngine.InitializeModules()
2024-08-22T16:24:29.3625417Z	      EPiServer.Core.ContentNotFoundException: Content with Guid "cb9f817f-139b-4db7-957f-d84ad527d3bc" was not found
2024-08-22T16:24:29.3625505Z	         at EPiServer.Core.Internal.DefaultContentLoader.Get[T](Guid contentGuid, LoaderOptions loaderOptions)
2024-08-22T16:24:29.3625599Z	         at EPiServer.Core.Internal.DefaultContentLoader.Get[T](Guid contentGuid)
2024-08-22T16:24:29.3625677Z	         at EPiServer.Core.Internal.DefaultContentRepository.Get[T](Guid contentGuid)
2024-08-22T16:24:29.3625904Z	         at EPiServer.Forms.EditView.Internal.MigrationService.UpdateMissingUploadFolderACL()
2024-08-22T16:24:29.3626011Z	         at EPiServer.Forms.EditView.JobScheduler.UpdateUploadFolderACLJob.Execute()
2024-08-22T16:24:29.3626093Z	         at EPiServer.Forms.EditView.InitializationModule.TryExecuteUpdateFolderACLJob()
2024-08-22T16:24:29.3626195Z	         at EPiServer.Forms.EditView.InitializationModule.Initialize(InitializationEngine context)
2024-08-22T16:24:29.3626283Z	         at EPiServer.Framework.Initialization.Internal.ModuleNode.<>c__DisplayClass4_0.<Initialize>b__0()
2024-08-22T16:24:29.3626385Z	         at EPiServer.Framework.Initialization.Internal.ModuleNode.Execute(Action a, String key)
2024-08-22T16:24:29.3626574Z	         at EPiServer.Framework.Initialization.Internal.ModuleNode.Initialize(InitializationEngine context)
2024-08-22T16:24:29.3626689Z	         at EPiServer.Framework.Initialization.InitializationEngine.InitializeModules()

In MigrationService.cs the code is iterating all upload asset folder owned by a content that inherits IFileUploadElementBlock by checking ContentOwnerID.

if (contentAssetFolder != null && !(contentAssetFolder.ContentOwnerID == Guid.Empty) && this._contentRepository.Service.Get<IContent>(contentAssetFolder.ContentOwnerID) is IFileUploadElementBlock)

However the if statement uses IContentRepository.Get instead of IContentRepository.TryGet and in my case the owner content must have been deleted because this is where the code throws exception.

The fix for this is pretty simple thought. I created my own version of MigrationService.cs

public class MigrationServiceWithTryGet : MigrationService
{
    private Injected<IContentTypeRepository> _contentTypeRepository;
    private Injected<IContentRepository> _contentRepository;
    private Injected<IContentModelUsage> _contentModelUsage;
    private Injected<IContentSecurityRepository> _contentSecurityRepository;


    public override void UpdateMissingUploadFolderACL()
    {
        var contentFolderType = _contentTypeRepository.Service.Load<ContentFolder>();
        var contents = _contentModelUsage.Service.ListContentOfContentType(contentFolderType);
        var contentReferences = contents.Select(x => x.ContentLink.ToReferenceWithoutVersion()).Distinct();

        foreach (var contentLink in contentReferences)
        {
            var contentFolder = _contentRepository.Service.Get<ContentFolder>(contentLink);
            if (contentFolder != null && (object)contentFolder.ParentLink != null && contentFolder.Name == "Uploaded Files")
            {
                var contentAssetFolder = _contentRepository.Service.Get<ContentAssetFolder>(contentFolder.ParentLink);
                if (contentAssetFolder != null && !(contentAssetFolder.ContentOwnerID == Guid.Empty) &&
                    // The 'TryGet' instead of just 'Get' is the difference between this and the optimizely original code
                    _contentRepository.Service.TryGet<IContent>(contentAssetFolder.ContentOwnerID, out var fileUploadElementBlock) && fileUploadElementBlock is IFileUploadElementBlock)
                {
                    IContentSecurityDescriptor securityDescriptor = contentFolder.GetContentSecurityDescriptor();
                    ContentAccessControlList contentSecurityDescriptor = [];
                    if (securityDescriptor.Entries.Any(entry => entry.Name.Equals(EveryoneRole.RoleName, StringComparison.OrdinalIgnoreCase)))
                    {
                        foreach (AccessControlEntry entry in securityDescriptor.Entries)
                        {
                            if (!entry.Name.Equals(EveryoneRole.RoleName, StringComparison.OrdinalIgnoreCase))
                                contentSecurityDescriptor.Add(entry);
                        }

                        _contentSecurityRepository.Service.Save(contentFolder.ContentLink,
                            contentSecurityDescriptor, SecuritySaveType.Replace);
                    }
                }
            }
        }
    }
}

And then forwarded the original service to my own in Startup.cs

services.AddSingleton<MigrationServiceWithTryGet>().Forward<MigrationServiceWithTryGet, MigrationService>();
#327918
Aug 23, 2024 10:09
Vote:
 

Thanks for sharing your finding & solution, and apologies for the inconvenience it has caused. I will file a bug for this 

#327923
Aug 23, 2024 11:58
Quan Mai - Aug 23, 2024 13:49
I created a fix for this and the linked bug and sent it to the development team
Vote:
 

The bug is now fixed and will be in an upcoming release

#328075
Aug 26, 2024 13:46
* 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.