Tracking Static Constructor Execution

7k views Asked by At

I'm running into a problem here where a static constructor of one of my classes is being called before it should be. (I.e, DI/IoC isn't set up and it's getting null/exceptions back from the service locator).

I unfortunately don't have a lot of control over the static constructor, don't ask me why it's relying on DI/IoC to be set up, but it is.

In my app, nothing should be referencing this class static or otherwise before my IoC is ready to go, but the static constructor is executing anyway.

Is there an easy way to determine what line caused the constructor to execute? Note: I cannot breakpoint in the static constructor because this is all happening before the remote debugger for ASP.NET can attach to the web server (in Global.asax.cs)

5

There are 5 answers

2
santiagoIT On BEST ANSWER

You have no control as to when the static constructor is executed. Move whatever you are doing from your constructor to a static Initialize() function. Call that one whenever you are ready. Do not depend on when the static constructor is executed.

Check this link

Static constructors have the following

properties:

A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.

A static constructor cannot be called directly.

The user has no control on when the static constructor is executed in the program.

1
leppie On

As always, use:

Debugger.Break()
0
Naveen On

This could be done using Windbg and sosex. Here is the sample code

using System;
namespace Code
{
class Test
{
  public static int i;
  static Test()
  {
    i = 10;
    Console.WriteLine(i);
  }
  static void Main()
  {
    Console.WriteLine(Test.i);
    Console.Read();
  }
}
}

And here are the steps

  1. Attach the process to windbg
  2. Load sosex using .load sosex
  3. Next issue the command !mbm *Code.Test..cctor*
  4. The debugger breaks on call to the static constructor after which you could issue !mk to get the callstack

Here is the output from !mk for the above sample

0:000> !mk
Thread 0:
     ESP              EIP
00:M 000000000026def8 000007ff00150120 Code.Test..cctor()(+0x0 IL)(+0x0 Native)
01:U 000000000026df00 000007fef43a10b4 clr!CallDescrWorker+0x84
02:U 000000000026df40 000007fef43a11c9 clr!CallDescrWorkerWithHandler+0xa9
03:U 000000000026dfc0 000007fef43a32b4 clr!DispatchCallDebuggerWrapper+0x74
04:U 000000000026e060 000007fef43aafdf clr!MethodTable::RunClassInitEx+0x1ff
05:U 000000000026e1b0 000007fef43aaca8 clr!MethodTable::DoRunClassInitThrowing+0x55e
06:U 000000000026ec70 000007fef43a3470 clr!MethodTable::CheckRunClassInitThrowing+0xe3
07:U 000000000026eca0 000007fef44cb848 clr!MethodDesc::DoPrestub+0x587
08:U 000000000026edb0 000007fef43a23f3 clr!PreStubWorker+0x1df
09:U 000000000026ee70 000007fef4362d07 clr!ThePreStubAMD64+0x87
0a:U 000000000026ef40 000007fef43a10b4 clr!CallDescrWorker+0x84
0b:U 000000000026ef80 000007fef43a11c9 clr!CallDescrWorkerWithHandler+0xa9
0c:U 000000000026f000 000007fef43a1245 clr!MethodDesc::CallDescr+0x2a1
0d:U 000000000026f230 000007fef44a1675 clr!ClassLoader::RunMain+0x228
0e:U 000000000026f480 000007fef44a17ac clr!Assembly::ExecuteMainMethod+0xac
0f:U 000000000026f730 000007fef44a1562 clr!SystemDomain::ExecuteMainMethod+0x452
10:U 000000000026fce0 000007fef44a3dd6 clr!ExecuteEXE+0x43
11:U 000000000026fd40 000007fef44a3cf3 clr!CorExeMainInternal+0xc4
12:U 000000000026fdb0 000007fef4527365 clr!CorExeMain+0x15
13:U 000000000026fdf0 000007fef6883309 mscoreei!CorExeMain+0x41
14:U 000000000026fe20 000007fef6915b21 MSCOREE!CorExeMain_Exported+0x57
15:U 000000000026fe50 0000000077a6f56d KERNEL32!BaseThreadInitThunk+0xd
16:U 000000000026fe80 0000000077ba3021 ntdll!RtlUserThreadStart+0x1d

HTH

0
Chingiz Musayev On

Maybe you should skip using static constructor? Is it necessarily?

public class SomeClass
{
    private static bool IsInizialized = false;

    public SomeClass()
    {
        if (!IsInizialized)
        {
            // static constuctor thread safe but this doesn't
            //
            lock (this)
            {
                if (!IsInizialized)
                {
                    IsInizialized = true;
                    // all what static constructor does
                }
            }
        }
    }
}
2
DSR On

Below is my static constructor debugging experience,

When I was trying to debug by placing a breakpoint on the line where the static field had referenced, I was not getting debug control on the static constructor.

I kept breakpoint on the static constructor entrance, removed the breakpoint from the line where the static field had referenced. Now Debug control started coming into the static constructor code.

This image shows how your editor with breakpoints would look like