Disclaimer: This website requires Please enable JavaScript in your browser settings for the best experience.

HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideLegal TermsGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Initialize CMS

Describes the initialization system in the Optimizely platform, which is used by Optimizely Content Management System (CMS 11), Optimizely Customized Commerce version 13, and third-party and customized modules used with Optimizely products.

Optimizely designed and implemented the CMS initialization system for the sole initialization mechanism for CMS internal code and third-party and custom modules. The initialization system has the following:

  • A discovery mechanism to determine which modules should be part of the initialization process.
  • A dependency sorting algorithm that decides the order of execution.
  • An execution engine that executes the modules.
  • Handling of re-execution of initialization modules (by hooking into ASP.NET) in the occurrence of exceptions during startup.
  • The  EPiServer.Framework.Initialization namespace, in the EPiServer.Framework assembly.

Discovery mechanism

Scanning the assemblies lets you locate the initialization modules in a CMS application.

The scanning is primarily using an attribute-based discovery system. CMS scans assemblies loaded in the current AppDomain for initialization modules, including assemblies in the bin folder, because by default, the ASP.NET config section <system.web>/<compilation>/<assemblies> contains the configuration <add assembly="*"/>, which causes the ASP.NET build system to pull in assemblies in the bin folder.

To have a discoverable initialization module, you need to add the [InitializableModule] or [ModuleDependency(...)] attribute to your class. The class also needs to implement the IInitializableModule interface.

The IInitializableHttpModule and IConfigurableModule interfaces extend the IInitializableModule. The assembly scanning process supports filtering logic, reducing the number of assemblies scanned. See the filtering section in this topic for information.

Dependency sorting

If your application has a dependency on one or more existing initialization modules, then explicitly state this dependency by using the [ModuleDependency(typeof(ModuleThatIDependOn))] attribute. The dependency sorting uses this to ensure it executes the modules in the correct order. You can define multiple modules on which the application is dependent. For example, in CMS, you can take a dependency on EPiServer.Web.InitializationModule to make sure it initializes any CMS functionality before your module.

It sorts the modules and executes the modules in the correct dependency order.

If the application has defined circular dependencies or dependencies to non-existing modules, you receive an exception upon application startup.

Execution engine – InitializationEngine

InitializationEngine (resides in the namespace EPiServer.Framework.Initialization) is responsible for executing the list of modules the dependency sorting algorithm created. As described in the IInitializableModule.Initialize method, it is guaranteed that the Initialize method gets called only once (unless the method error occurs).

The initialization engine is a simple state machine that logs information about state changes and reports the initialization methods that were executed. See the Logging section in this document for information.

In case of an exception, the system stops executing initialization code and waits for the next incoming request, then retries the failing Initialization method. This behavior ensures the system does not start up in a partially initialized state.

After it executes the initialization methods, it raises an InitComplete event, which lets you perform post-initialization actions. For information,  see the InitComplete event section.

Start the initialization system

Call the initialization system from the first point of entry in the application. In CMS, this is handled automatically in the EPiServer.Global base class, the base class for Global.asax.cs. The call to the initialization system is placed at that point because it is the first piece of code under CMS’s control that ASP.NET invokes. If errors occur from a startup module, CMS tries the initialization again at the next BeginRequest event.

The major advantage of using the earlier initialization point is that it executes before Application_Start, which has the application fully initialized and usable from within Application_Start.

ASP.NET 4 can automatically startup and proactively initialize a web application without waiting for an external client to hit the web server, providing a faster response time. You do not need custom scripts to “warm up” the server and get data caches ready. This feature works with ASP.NET applications, including ASP.NET Web Forms and ASP.NET MVC-based applications. Find out more about this: ASP.NET feature.

Assembly scan and filter

When the initialization system looks for modules, it relies on a common type scanning system based on the standard .NET reflection APIs for loading and composition. The basic idea is to scan assemblies that are part of the application, except .NET Framework assemblies. The EPiServer.Framework.Initialization.InitializationModule.Assemblies static property exposes the assembly list. You can attribute an assembly with [PreventAssemblyScan] to exclude it from the scanning process.

Optimizely products use the same scanning process as the initialization system when discovering plug-ins. It is important to remember when you decide which assemblies are scanned by the Optimizely Framework.

Because scanning assemblies for types can be time-consuming, it uses a disk-based cache and stores it in the per-site folder Temporary ASP.NET Files. Scanning loads the types it discovers into a lookup, implementing the ITypeScannerLookup interface in EPiServer.Framework.TypeScanner namespace. Types that define plug-in systems, such as Optimizely CMS, use an assembly attribute TypeScannerRegistration to register plug-in types. Do not use the TypeScannerRegistration attribute to register plug-ins; only to register new plug-in types. A consolidated type scanning system requires a single cached sweep over all assemblies for all products to initialize themselves.

Customize assembly scanning with configuration

You can configure optional settings in the <episerver.framework> section of web.config to customize the assembly scanning process.

<scanAssembly forceBinFolderScan="true" />

Use this section to customize the assembly scanning process. Consider it as an additional filter on top of the assemblies normally loaded by ASP.NET as controlled by the <system.web> /<compilation>/<assemblies> section. The bulk of the configuration usually resides in the systems web.config file.

If you want to exclude specific assemblies from the normal scanning process (as described in the previous section), see the following example:

<scanAssembly forceBinFolderScan="true">
   <add assembly="*" />
   <remove assembly="MyAssembly" />
   <remove assembly="MyAssembly2" />
</scanAssembly>

This example includes all assemblies by the <add assembly="*" /> directive (except those filtered by attributes described above) except for MyAssembly and MyAssembly2. The second mode of usage is to only scan specific assemblies by adding configuration similar to this as follows:

<scanAssembly forceBinFolderScan="true">
      <add assembly="EPiServer.Framework" />
      <add assembly="EPiServer.Data" />
      <add assembly="EPiServer.Events" />
      <add assembly="EPiServer.Shell" />
      <add assembly="EPiServer" />
      <add assembly="EPiServer.Enterprise" />
      <add assembly="EPiServer.Cms.Shell.UIscanAssembly">
</scanAssembly>

This example excludes any other assemblies from being scanned. The selection of assemblies above represents assemblies delivered with CMS with initialization modules (these must be present for CMS to work properly).

InitComplete event

Sometimes, you might want to call your initialization module again after the initialization process is complete. A typical use case is to attach event handlers to an instance property that third-party code can override.

To attach to the InitComplete event, write your Initialize method as follows:

public void Initialize(InitializationEngine context) {
  context.InitComplete += InitCompleteHandler;
  StartThisModule();
}

When all initialization modules have executed, the InitComplete event is raised. The InitComplete event is handled in a slightly non-standard way. When an event handler executes without error, the initialization system removes it from the InitComplete event. So do not detach from the InitComplete event in your Uninitialize method.

Although this procedure in the initialization system may seem peculiar, it verifies that if an InitComplete event handler has an error CMS can re-execute the InitComplete event on the next request without re-invoking the already executed event handlers.

Logging

Add the following configuration to episerverlog.config to enable logging of the initialization engine:

<logger name="EPiServer.Framework.Initialization">
  <level value="All" />
</logger>