---
title: Run code on application startup
related:
  - https://docs.kentico.com/documentation/developers-and-admins/customization/handle-global-events.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

Xperience customization scenarios sometimes require you to call specific system API during application startup to achieve the desired behavior. Some examples include:

- assigning handlers to [global system events](https://docs.kentico.com/documentation/developers-and-admins/customization/handle-global-events.md)
- adding custom implementations of objects to global collections (e.g., [personal data erasers](https://docs.kentico.com/documentation/developers-and-admins/data-protection/personal-data-erasure.md) and [collectors](https://docs.kentico.com/documentation/developers-and-admins/data-protection/personal-data-collection.md))
- registering custom JavaScript modules containing [admin UI customizations](https://docs.kentico.com/documentation/developers-and-admins/customization/extend-the-administration-interface.md)

The system provides a convenient entry point for such code in the form of **code-only modules**. Modules are [custom classes](https://docs.kentico.com/documentation/developers-and-admins/customization/integrate-custom-code.md) that provide the following methods:

- `OnInit` – the system executes the code during the initialization (start) of the application. A typical example of `OnInit` code is assigning handler methods to system events.
- `OnPreInit` – the system executes the code before `OnInit`. Does _not_ support any operations that require access to the database. For example, can be used to register [custom data types](https://docs.kentico.com/documentation/developers-and-admins/customization/field-editor/add-custom-data-types.md) or access the application's service collection.

Xperience collects all module classes during application startup and executes their `OnInit` and `OnPreInit`  methods. The initialization order of modules is not guaranteed and cannot be controlled (modules can be initialized in a different order every time the application starts). For this reason, we don't recommend relying on the initialization order in your custom code.

## Run custom code on application startup

To run custom code on application startup:

1. Open your Xperience project in Visual Studio.
2. Create a custom class that inherits from `CMS.DataEngine.Module`.

   - See [Integrate custom code](https://docs.kentico.com/documentation/developers-and-admins/customization/integrate-custom-code.md) for best practices about adding custom classes to Xperience projects.
3. Define the constructor of the module class:

   - Inherit from the base constructor.
   - Enter the code name of the module as the base constructor parameter. The code name must be unique within the application.
4. Register the module class using the `RegisterModule` assembly attribute.
5. Override the `OnInit` or `OnPreInit` method (follow the guidelines of your particular customization scenario) and call the required startup code inside.
   - Override `OnInit(ModuleInitParameters)` to access the application's service container via [IServiceProvider](https://learn.microsoft.com/en-us/dotnet/api/system.iserviceprovider), for example if you need to resolve dependencies required for the module's code.

     ```csharp
     protected override void OnInit(ModuleInitParameters parameters)
     {
         // Resolve services via IServiceProvider. e.g., ILogger
         parameters.Services.GetRequiredService<ILogger<CustomModule>>();
         ...
     }
     ```
   - Override `OnPreInit(ModuleInitParameters)` if you wish to access the application's [IServiceCollection](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.iservicecollection) during module pre-initialization. For example, you can dynamically configure the application's startup options.

     ```csharp
     protected override void OnPreInit(ModulePreInitParameters parameters)
     {
         // Access IServiceCollection, e.g., to configure startup options like EmailQueueOptions
         parameters.Services.Configure<EmailQueueOptions>(...);
         ...
     }
     ```

The system executes the methods when collecting registered modules during application startup.

## Example

The following example resolves dependencies on other services from `IServiceProvider` accessed via `ModuleInitParameters`.

```csharp title="Service resolution using ModuleInitParameters"
using CMS;
using CMS.Core;
using CMS.DataEngine;
using CMS.OnlineForms;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

[assembly: RegisterModule(typeof(CustomModule))]

public class CustomModule : Module
{
    private ILogger<CustomModule> logger;

    // Module class constructor, inherits from the base constructor with the code name of the module as the parameter
    public CustomModule() : base(nameof(CustomModule))
    {
    }

    protected override void OnInit(ModuleInitParameters parameters)
    {
        // Accesses 'IServiceProvider' via ModuleInitParameters and resolves 'ILogger'
        logger = parameters.Services.GetRequiredService<ILogger<CustomModule>>();

        // Registers an event handler
        BizFormItemEvents.Insert.After += BizFormItem_Insert_After;
    }

    private void BizFormItem_Insert_After(object sender, BizFormItemEventArgs e)
    {
        // Logs an information event whenever a form is submitted
        string message = $"The '{e.Item.BizFormInfo.FormDisplayName}' form was submitted.";
        logger.LogInformation(new EventId(0, "FORM_SUBMITTED"), message);
    }
}
```

## Code analyzer support

The _Kentico.Xperience.Core_ [NuGet package](https://docs.kentico.com/documentation/developers-and-admins/development/website-development-basics/configure-new-projects/xperience-by-kentico-nuget-packages.md) contains a code analyzer that advocates best practices when implementing custom modules. The analyzer reports when a module defines both a parameterless `OnInit()` or `OnPreInit()` method and the corresponding overload with initialization parameters (`OnInit(ModuleInitParameters)` or `OnPreInit(ModulePreInitParameters)`).

The diagnostic uses _Information_ severity and does not block compilation. If you see this diagnostic, we recommend consolidating your module startup logic into a single parameterized method to improve clarity and maintainability.

All Kentico-specific analyzer rules begin with the _KXA_ prefix.
