Executing code before Main

Exploring the ways code can be execute before the Main method is called

Home DailyDrop

Daily Knowledge Drop

In C#, the Main method is the entry point of an application - however there are a few scenarios where it is possible to have code executed before the Main method


Base application

Below is the base application we will build on. This is a simple console application which outputs to the console when the Main method is called.

public class Program
{
    public static void Main()
    {
        Console.WriteLine("App started => Main");
    }
}

The output when the application is run:

    App started => Main

Before Main

Startup hook

There is an environment variable, DOTNET_STARTUP_HOOKS which can be set to execute code before the application's Main method is called.

This environment variable can contain a semi-colon separated list of dll paths. These dll's need to contain class(es) which conform to a specific set of rules:

  • The class must be outside of any namespace
  • The class must contain a static method called Initialize. This method is called on startup of the application.

Below, a class has been defined in a separate project, which outputs to StartupHook.dll.

internal class StartupHook
{
    static StartupHook() => Console.WriteLine("StartupHook => static constructor");

    public static void Initialize() => Console.WriteLine("StartupHook => Initialize");
}

When executing the base application, the environment variable DOTNET_STARTUP_HOOKS can now be set to the full path of the StartupHook.dll

Below is a example of the launchSettings.json file

{
  "profiles": {
    "BeforeMain": {
      "commandName": "Project",
      "environmentVariables": {
        "DOTNET_STARTUP_HOOKS": "C:\\StartupHook.dll"
      }
    }
  }
}

The output of the base application is now:

    StartupHook => static constructor
    StartupHook => Initialize
    App started => Main

ModuleInitializer

Static method(s) can be decorated with the ModuleInitializer attribute, which indicates to the compiler these methods should be invoked during the containing application's initialization (start-up).

In the same project as the Program class above:

public class ModInit
{
    public ModInit()
    {
        Console.WriteLine("ModInit => constructor");
    }

    static ModInit()
    {
        Console.WriteLine("ModInit => static constructor");
    }

    [ModuleInitializer]
    public static void ExecuteInitCode() => 
        Console.WriteLine("ModInit => ExecuteInitCode");
}

The output when the application is run is now as follows:

    StartupHook => static constructor
    StartupHook => Initialize
    ModInit => static constructor
    ModInit => ExecuteInitCode
    App started => Main

Static Program constructor

A static constructor on the Program class (the class containing the Main method) can also be used to execute code before the Main method:

public class Program
{
    static Program()
    {
        Console.WriteLine("Program => static constructor");
    }

    public static void Main()
    {
        Console.WriteLine("App started => Main");
    }
}

The output when the application is run is now as follows:

    StartupHook => static constructor
    StartupHook => Initialize
    ModInit => static constructor
    ModInit => ExecuteInitCode
    Program => static constructor
    App started => Main

Notes

Today we looked at the various ways code can be executed before Main and the order in which the various code is executed. There are a number of different options depending on the use case, from executing code in an external DLL, initializing modules in the same code base, or just having the Program constructor execute first.


References

Executing code before Main in .NET

Daily Drop 54: 18-04-2022

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net main execution