2

I've read several of the other posts here about this, but my problem seems to fly in the face of the general wisdom posted here (Is the order of static class initialization in C# deterministic?) and several related posts.

I've got an ASP.Net 4.0 application, and my Application_Start() method runs through touching a lot of things to get them set up. One of those things is initializing our db connection string for our DAL, others initializing other variables. A couple of days ago our release builds started blowing up, and after adding a lot of debug logging, the cause turned out to be a new static initizalizer being called before Application_Start() was officially entered and trying to access our DAL before it was initialized. And this seems to run afoul of what I see in other posts here about the order of execution for static constructors and initializers.

Specifically, the static initializers are not being run at the point in the code where they are called; the stack traces in the release build indicate that release compilation shuffles them up to be part of entering Application_Startup(). In other words the stack trace when it blows up shows Application_Startup() on the stack - but no line number associated with it. The stack trace for the DAL initialization does show the line number.

To flesh out some pseudo code, we have

Application_Start()
{
    DAL.Inst.GetSetting("ConnectionString"); // tickles the singleton to get the DAL initialized.

    // numerous other lines of code    
    if (!AppUtil.IsAdminAccountSetup)
    { // Do admin account setup
    }
    // More code
}

public class DAL
{
    private static DAL _singleton;

    static DAL()
    {
       _singleton = new DAL();
       _singleton.Initialize();
    }

    public static DAL Inst
    {
        get { return _singleton; }
    }
    // all the other methods
}

public class AppUtil
{
    private static bool _isAdminSetup = InitializeAdminSetup();
    public static bool IsAdminAccountSetup
    {
       get { return _isAdminSetup; }
    }

    private static bool InitializeAdminSetup()
    {
        // Call DAL for query
    }

    private static bool _isProductRegistered = InitializeProdReg();
    public static bool IsProductRegistered
    {
        get { return _isProductRegistered; }
    }

    private static bool InitializeProdReg()
    {
        // Call DAL for query
    }
}

AppUtil recently had the IsProductRegistered boolean added, and that seems to be when things headed south.

AppUtil.IsProductRegistered is not called in Application_Start(), but when we look at stack traces about the order of queries to the DAL, we see the initializer for AppUtil.IsProductRegistered calling the DAL (before DAL.Inst gets touched) and from Application_Start() (no line number).

Then we see the connection string getting initialized as part of the DAL static constructor, and that traces back to the DAL.Inst reference in Application_Start() - and here it does show the line number.

If we change both of the static initialzers in AppUtil to a single static constructor, things go back to being initialized in reference order and the blow-up goes away.

But the whole situation flies in the face of what I've read about what .Net says it will do.

Sorry for the information barf, but I hoped to have enough detail to make the conundrum clear.

Community
  • 1
  • 1
user1664043
  • 695
  • 5
  • 14
  • 1
    Why "static initizalizer ... called before Application_Start" surprises you? The only guarantee is static constructors will be called before first usage of the class. Not sure what type of advice you are looking in your post except "don't rely on any particular order/time of call for static constructors". – Alexei Levenkov Mar 06 '14 at 23:43
  • @AlexeiLevenkov A static constructor will only run immediately before the first access. A field initializer on a class without static constructor can run earlier. – Loki Mar 06 '14 at 23:51
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Mar 07 '14 at 00:09

2 Answers2

4

There is a big difference between initializers on a class with a static constructor and without. On classes without a static constructor they can run at any time prior to the first access, much earlier if the runtime so decides. With a static constructor they can only run immediately prior to the first access.

DAL has a static constructor so it's guaranteed to initialize on first access and no earlier.

AppUtil has no static constructor, so it can run as early as it likes, in particular it can run before you initialized DAL.

Your immediate problem should disappear if you add a static constructor to AppUtil even if it's empty.

You should read C# and beforefieldinit by Jon Skeet, where he explains this difference in detail.

To quote the specification:

If a static constructor (§10.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.

The static constructor for a closed class type executes at most once in a given application domain. The execution of a static constructor is triggered by the first of the following events to occur within an application domain:

  • An instance of the class type is created.
  • Any of the static members of the class type are referenced.

Still this kind of initialization pattern is a bad idea on many levels. These initializers are hard to debug, can change their order on a whim.

You should not use static fields for this kind of state in the first place. Create a single instance of these classes during your initialization code instead of using a classic singleton which uses state from outside its own class to initialize. Or even better, use proper Dependency Injection. These kind of services is the place where DI and IoC shine.

Community
  • 1
  • 1
Loki
  • 421
  • 2
  • 4
  • +1: good info from specification on precise timing of static constructor. Personally from practical point of view it is not much different than "at random point before first usage". – Alexei Levenkov Mar 07 '14 at 00:24
  • Thanks for the Skeet ref; I'll read it. I'd thought static initializers a) also ran prior to first use and that b) as of .Net 4.0 they're unhooked from the static constructor. When we moved from .Net 2 to 4, we got bit in the opposite way; we had an odd dependency chain where initing DAL happened because touching a diff static member of a diff class also ran that class' static cctor which happened to touch DAL; when we went to 4.0, touching the other static didn't end up getting DAL inited. That's why we put a tickle at the top of Application_Start. Luckily that one repro'ed in Debug – user1664043 Mar 07 '14 at 15:11
  • Just amending the above comment. Went and looked up our old .net 4 transition bug, and it was another case of initializers w/no static constructor and the diff between 2 and 4 seemed to be that in 2, it was "touch one, initialize all" where 4 was more lazy loading and the different statics were decoupled. Under 2 we got away with it because touching Foo.bar1 ended up also initializing Foo.bar2 which happened to initialize our DAL. When we went to 4, touching Foo.bar1 no longer initialized Foo.bar2 along for the ride opening the hole. – user1664043 Mar 07 '14 at 20:51
0

In addition to Loki's comments. You are potentially going to burnt very badly if dependant on statics in a DAL. eg Entity framework. Do not attempt this without understanding the .Net ASP pipeline and how threads are used. You must consider what is going on in the app pool. The lifetime of the app pool. Thread safety. The app pool allocates incoming calls to threads. So you must make the statics thread safe. You may need a custom initializer that gets called for every request no just on APP start.
As you are discovering app start could already have run on a previous request.

for your consideration:

    //Global asax handlers   
    public override void Init() {
        base.Init();
        // handlers managed by ASP.Net during Forms authentication
        BeginRequest += new EventHandler(BeginRequestHandler);
      //  PostAuthorizeRequest += new EventHandler(PostAuthHandler);
        EndRequest += new EventHandler(EndRequestHandler);
    }

Consider ASP.NET controller constructors that "renew" contexts left over from last call.

Consider how you will protect your static. // thread safe ????

  private static Object _bgalock = new Object();
  [ThreadStatic]  // thread based static to avoid disasters....
  private static sometypeStaticUsedGlobally _ouch;

  // Then Get and Set static with lock
phil soady
  • 11,043
  • 5
  • 50
  • 95