Static Constructor Exceptions: A Rare Culprit That Requires App Restarts

This post has been republished via RSS; it originally appeared at: IIS Support Blog articles.

If a static constructor throws an exception, the runtime doesn't invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain. So, only way to come out this situation is Application recycle/restarts. 

This can be a very rare scenario occurring intermittently and can become difficult debug. I have seen this issue happening WCF or Asp.Net impersonation.

 

Consider below exception:

 

manojdixit_0-1697610642936.png

System.Security.SecurityException: Requested registry access is not allowed. Once this occurs, every user gets the exception, until I restart the application.

 

Anyone who has knowledge of debugging, obvious try to see the registry path being accessed using tools like Process Monitor - Sysinternals | Microsoft Learn. The problem when I browse the page again with procmon running, I don't see any call made to registry of interest.

This can also happen to file access. So how to debug this? 

First step is to understand below:

  • Is the exception originating from a constructor? 
  • Is the constructor marked as static?
  • Are we using User Impersonation (WCF/Asp.Net)?

In my case, all the above is true. Let's look at the source code:

 

manojdixit_1-1697611392958.png

for demonstration purposes, I'm using an aspx page as my source code. I've enabled Asp.Net impersonation (Impersonation in ASP.NET applications - ASP.NET | Microsoft Learn) with IIS classic pipeline.

I have a class with a static constructor accessing a restricted registry folder. This can be a logwriter, DBcontext etc. in real world. Since I have impersonation enabled, this code executes with logged user context.

 

Note the below points about static constructors - Static Constructors - C# Programming Guide - C# | Microsoft Learn:

  • The user has no control on when the static constructor is executed in the program.
  • A static constructor is called automatically. It initializes the class before the first instance is created or any static members declared in that class (not its base classes) are referenced. A static constructor runs before an instance constructor. If static field variable initializers are present in the class of the static constructor, they're executed in the textual order in which they appear in the class declaration. The initializers run immediately prior to the execution of the static constructor.
  • If a static constructor throws an exception, the runtime doesn't invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain. Most commonly, a TypeInitializationException exception is thrown when a static constructor is unable to instantiate a type or for an unhandled exception occurring within a static constructor. For static constructors that aren't explicitly defined in source code, troubleshooting may require inspection of the intermediate language (IL) code.

So, if the first request when the process starts is made by a user with no access to the registry of interest, constructor throws exception.

The constructor is not invoked again even if a user with access browses the page. When the App is restarted and a user with access makes the request, the constructor runs fine. This is what makes it difficult to debug, the intermittency of the issue!

 

How to resolve this:

  • If you control the source code, try wrapping the static constructor in try/catch block, but this might not help with actual functionality of the class. 
  • If you don't control the source code of the class (for example 3rd party library), with some sort of logging, the first user who received this exception can be determined.
  • Either way, appropriate permissions for the resource can be given to all intended users of the Application.
  • I have seen libraries using %TEMP% variable to write some logs. If used in IIS hosted apps, it will resolve the C:\Windows\Temp if the user profile is not loaded (Application Pool Identities | Microsoft Learn). Even if user profile is loaded, incoming user might not have access to the folder. So right permissions given to all intended users.

Happy debugging!

 

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.