This topic describes the initialization system in the Optimizely platform, which is used by Optimizely Content Management System (CMS), Optimizely Customized Commerce, and third-party and customized modules used with Optimizely products. You can develop your own initialization module.
The CMS initialization system is designed and implemented with the purpose of being the sole initialization mechanism to use for CMS internal code and third-party and custom modules. The initialization system comprises 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 occurence of exceptions during startup.
EPiServer.Framework.Initialization` namespace, in the `
## Discovery mechanism
You can locate the initialization modules in an CMS application through scanning assemblies.
The scanning is primarily using an attribute-based discovery system. CMS scans all assemblies loaded in the current `
AppDomain` for initialization modules. This includes all 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 all 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.
IInitializableHttpModule` and `
IConfigurableModule` interfaces extend the `
IInitializableModule`. To speed up the initialization process, the assembly scanning process supports some filtering logic which reduces the number of assemblies that are 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. This is used by the dependency sorting to ensure that all modules are executed 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 any CMS functionality has been initialized before your module.
The modules are then simply sorted, ensuring that the modules are executed 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 created by the dependency sorting algorithm. 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 all 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 that the system does not start up in a partially initialized state.
After all Initialization methods are executed successfully, an `
InitComplete` event is raised, which lets you perform post-initialization actions. For information, see the [InitComplete event section](🔗).
### How the initialization system is started
The initialization system should be called 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 is invoked by ASP.NET. If errors occur from a startup module, CMS tries the initialization again at the next `
The major advantage of using the earlier initialization point is that it is executed before **Application\_Start**, which has the application fully initialized and usable from within Application\_Start.
ASP.NET 4 comes with the ability to automatically startup and proactively initialize a web application without waiting for an external client to hit the web server. This provides a faster response time, and you do not need custom scripts to “warm up” the server and get data caches ready. This feature works with all types of ASP.NET applications – including both 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 all assemblies that are part of the application, with the exception of .NET Framework assemblies. This assembly list is exposed through the `
EPiServer.Framework.Initialization.InitializationModule.Assemblies` static property. 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. This is important to remember when you decide which assemblies are scanned by the Optimizely Framework.
Because scanning assemblies for types can be time-consuming, a disk-based cache is used, and is stored in the per-site folder _Temporary ASP.NET Files_. The types that were discovered during scanning are then loaded into a lookup implementing the `
ITypeScannerLookup` interface in `
EPiServer.Framework.TypeScanner` namespace. Types that define plug-in systems, such as Optimizely CMS, uses an assembly attribute `
TypeScannerRegistration` to register new plug-in types. Do not use the `
TypeScannerRegistration` attribute to register plug-ins; only to register new plug-in types. By having a consolidated type scanning system, a single cached sweep over all assemblies is required 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. Under this section, you find the following element:
Use this section to customize the assembly scanning process. It should be regarded 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:
This includes all assemblies by virtue of the <add assembly="\*" /> directive (except those filtered by attributes as 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:
This excludes any other assemblies from being scanned. The selection of assemblies above represent all assemblies delivered with CMS that have initialization modules (these assemblies must be present for CMS to work properly).
## InitComplete event
There are cases where you might want your own initialization module to be called again after the initialization process is complete. A typical use case is to attach event handlers to an instance property that may be overridden by third-party code.
To attach to the `
InitComplete` event, write your Initialize method as follows:
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 `
Although this procedure in the initialization system may seem peculiar, it is simply to verify 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 successfully executed event handlers.
Add the following configuration to _episerverlog.config_ to enable logging of the initialization engine: