Skip to main content

Back-End Development

Page Restrictions in an Initialization Module

Episerver connecting puzzle pieces
Managing your AllowedTypes (insert options) in Episerver can become overwhelming, depending on the strategy you take.
You can read about different options here:
but there is a strategy you can take for a very developer-friendly approach.
As highlighted on Epi World forum thread (Dylan McCurry and I worked together on the project where we implement this and we are using this on all projects moving forward ), you can actually manipulate the IAvailableSettingsRepository during initialization to define all of your restrictions in one place.

The Solution

Create a standard Episerver initialization module and implement Initialize() function.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
publicclass PageRestrictionInitialization : IInitializableModule
{
private IContentTypeRepository _contentTypeRepository;
private IAvailableSettingsRepository _availableSettingsRepository;
private ILogger _log;
publicvoidInitialize(InitializationEngine context)
{
}
publicvoidUninitialize(InitializationEngine context)
{
}
}
[InitializableModule] [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] public class PageRestrictionInitialization : IInitializableModule { private IContentTypeRepository _contentTypeRepository; private IAvailableSettingsRepository _availableSettingsRepository; private ILogger _log; public void Initialize(InitializationEngine context) { } public void Uninitialize(InitializationEngine context) { } }
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class PageRestrictionInitialization : IInitializableModule
{
    private IContentTypeRepository _contentTypeRepository;
    private IAvailableSettingsRepository _availableSettingsRepository;
    private ILogger _log;
    
    public void Initialize(InitializationEngine context)
    {
    }

    public void Uninitialize(InitializationEngine context)
    {
    }
}

We are using two helper functions that are making the code cleaner and easier to read and maintain.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
privatevoid DisallowAll<T>()
{
var page = _contentTypeRepository.Load(typeof(T));
var setting = new AvailableSetting
{
Availability = Availability.None
};
_availableSettingsRepository.RegisterSetting(page, setting);
}
private void DisallowAll<T>() { var page = _contentTypeRepository.Load(typeof(T)); var setting = new AvailableSetting { Availability = Availability.None }; _availableSettingsRepository.RegisterSetting(page, setting); }
private void DisallowAll<T>()
{
    var page = _contentTypeRepository.Load(typeof(T));

    var setting = new AvailableSetting
    {
         Availability = Availability.None
    };

    _availableSettingsRepository.RegisterSetting(page, setting);
}
DisallowAll() function will set a page type to not have any available pages to be inserted beneath of it. We are using this function to first set the availability to none and then set the availability how we want.
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
privatevoid SetPageRestriction<T>(IEnumerable<Type> pageTypes)
{
var page = _contentTypeRepository.Load(typeof(T));
var setting = new AvailableSetting
{
Availability = Availability.Specific
};
foreach(var pageType in pageTypes)
{
var contentType = _contentTypeRepository.Load(pageType);
setting.AllowedContentTypeNames.Add(contentType.Name);
}
_availableSettingsRepository.RegisterSetting(page, setting);
_log.Log(Level.Debug, $"{page.Name} restriction added.");
}
private void SetPageRestriction<T>(IEnumerable<Type> pageTypes) { var page = _contentTypeRepository.Load(typeof(T)); var setting = new AvailableSetting { Availability = Availability.Specific }; foreach (var pageType in pageTypes) { var contentType = _contentTypeRepository.Load(pageType); setting.AllowedContentTypeNames.Add(contentType.Name); } _availableSettingsRepository.RegisterSetting(page, setting); _log.Log(Level.Debug, $"{page.Name} restriction added."); }
private void SetPageRestriction<T>(IEnumerable<Type> pageTypes)
{
     var page = _contentTypeRepository.Load(typeof(T));

     var setting = new AvailableSetting
     {
            Availability = Availability.Specific
     };

     foreach (var pageType in pageTypes)
     {
            var contentType = _contentTypeRepository.Load(pageType);
            setting.AllowedContentTypeNames.Add(contentType.Name);
     }

     _availableSettingsRepository.RegisterSetting(page, setting);

     _log.Log(Level.Debug, $"{page.Name} restriction added.");
}

SetPageRestriction() function is where all the restrictions are done. You can pass the list of page types as a function argument and that those page types will be set as allowed page types for the passing page type type <T>.

Now we can implement the Initialize() function.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
publicvoidInitialize(InitializationEngine context)
{
_contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
_availableSettingsRepository = ServiceLocator.Current.GetInstance<IAvailableSettingsRepository>();
_log = LogManager.GetLogger();
var sysRoot = _contentTypeRepository.Load("SysRoot")as PageType;
var setting = new AvailableSetting
{
Availability = Availability.Specific,
AllowedContentTypeNames =
{
nameof(StartPage), // can't use custom interfaces with IContentTypeRepository
}
};
_availableSettingsRepository.RegisterSetting(sysRoot, setting);
// Disallow insertion for all product and article related pages
DisallowAll<ProductPage>();
DisallowAll<ArticlePage>();
DisallowAll<LandingPage>();
DisallowAll<FindSearchPage>();
// Home Page
SetPageRestriction<StartPage>(new List<Type>
{
typeof(ContainerPage),
typeof(StandardPage),
typeof(LandingPage),
typeof(FindSearchPage),
typeof(ProductPage)
});
// Landing Page
SetPageRestriction<LandingPage>(new List<Type>
{
typeof(ArticlePage),
typeof(NewsPage)
});
// Container Page
SetPageRestriction<ContainerPage>(new List<Type>
{
typeof(ContactPage)
});
// Product Page
SetPageRestriction<ProductPage>(new List<Type>
{
typeof(ContainerPage),
typeof(StandardPage)
});
}
public void Initialize(InitializationEngine context) { _contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>(); _availableSettingsRepository = ServiceLocator.Current.GetInstance<IAvailableSettingsRepository>(); _log = LogManager.GetLogger(); var sysRoot = _contentTypeRepository.Load("SysRoot") as PageType; var setting = new AvailableSetting { Availability = Availability.Specific, AllowedContentTypeNames = { nameof(StartPage), // can't use custom interfaces with IContentTypeRepository } }; _availableSettingsRepository.RegisterSetting(sysRoot, setting); // Disallow insertion for all product and article related pages DisallowAll<ProductPage>(); DisallowAll<ArticlePage>(); DisallowAll<LandingPage>(); DisallowAll<FindSearchPage>(); // Home Page SetPageRestriction<StartPage>(new List<Type> { typeof(ContainerPage), typeof(StandardPage), typeof(LandingPage), typeof(FindSearchPage), typeof(ProductPage) }); // Landing Page SetPageRestriction<LandingPage>(new List<Type> { typeof(ArticlePage), typeof(NewsPage) }); // Container Page SetPageRestriction<ContainerPage>(new List<Type> { typeof(ContactPage) }); // Product Page SetPageRestriction<ProductPage>(new List<Type> { typeof(ContainerPage), typeof(StandardPage) }); }
public void Initialize(InitializationEngine context)
{
    _contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
    _availableSettingsRepository = ServiceLocator.Current.GetInstance<IAvailableSettingsRepository>();
    _log = LogManager.GetLogger();

    var sysRoot = _contentTypeRepository.Load("SysRoot") as PageType;
    var setting = new AvailableSetting
    {
        Availability = Availability.Specific,
        AllowedContentTypeNames =
        {
            nameof(StartPage), // can't use custom interfaces with IContentTypeRepository
        }
    };
    _availableSettingsRepository.RegisterSetting(sysRoot, setting);

    // Disallow insertion for all product and article related pages
    DisallowAll<ProductPage>();
    DisallowAll<ArticlePage>();
    DisallowAll<LandingPage>();
    DisallowAll<FindSearchPage>();

    // Home Page
    SetPageRestriction<StartPage>(new List<Type>
    {
        typeof(ContainerPage),
        typeof(StandardPage),
        typeof(LandingPage),
        typeof(FindSearchPage),
        typeof(ProductPage)
    });

    // Landing Page
    SetPageRestriction<LandingPage>(new List<Type>
    {
        typeof(ArticlePage),
        typeof(NewsPage)
    });

    // Container Page
    SetPageRestriction<ContainerPage>(new List<Type>
    {
        typeof(ContactPage)
    });

    // Product Page
    SetPageRestriction<ProductPage>(new List<Type>
    {
        typeof(ContainerPage),
        typeof(StandardPage)
    });
}

I am using the Episerver Alloy demo website for this example and all the page types are from the Alloy project.

First, we get the SysRoot node as a page type and use it as a first page/node. Then we allow only the StartPage to be inserted under the root page and save the settings.

Next, we disallow inserting any page under the ProductPage, ArticlePage, LandingPage and FindSearchPage. Now we need to allow insertion for every page type how we want it. For this example I did that for the StartPage, LandingPage, ContainerPage and the ProductPage.

And that’s it.

 

In this way, you have a clean model for all page types and everything in one place and it’s easy to maintain and extend later on. And this concept consolidates to the first SOLID principles – Single Responsibility.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Nenad Nicevski

Nenad is a Certified Optimizely (former EPiServer) Content Cloud Developer. He is a full-stack developer focused on ASP.NET CMS technologies, mainly ASP.NET Core and ASP.NET with MVC. Nenad is no stranger to WordPress, Drupal 7/8, and Angular JS. In his free time, he loves to play basketball and guitar and make fun of himself to amuse his daughter!

More from this Author

Follow Us