As part of our daily jobs we provide support for several custom-developed SharePoint-based web applications, like purchase order workflows, etc. either. Few of them were developed for MOSS 2007 / SharePoint 2010, and then migrated to SharePoint 2013. The code quality reflects often not the best programming practices as well, to tell the through.
A weird error has arisen in one of that applications from a such coding anti-pattern caused us some headache recently.
Every once in a while the users complained, that the custom pages they use otherwise (for example, a day earlier) throw an exception. Restarting the IIS application pool for the SharePoint web application made the pages to function again, however we considered this as a simple quick-and-dirty workaround until we find out the real reason behind the issue.
In the ULS logs we found the following entries:
Application error when access /_layouts/CustomPages/YourPage.aspx, Error=List ‘Config’ does not exist at site with URL ‘http://YourSharePoint’.
Microsoft.SharePoint.Client.ResourceNotFoundException: List ‘Config’ does not exist at site with URL ‘http://YourSharePoint’.
Getting Error Message for Exception System.Web.HttpUnhandledException (0x80004005): Exception of type ‘System.Web.HttpUnhandledException’ was thrown. —> System.TypeInitializationException: The type initializer for ‘Company.Custom.Config’ threw an exception. —> System.ArgumentException: List ‘Config’ does not exist at site with URL ‘http://YourSharePoint’. —> Microsoft.SharePoint.Client.ResourceNotFoundException: List ‘Config’ does not exist at site with URL ‘http://YourSharePoint’. — End of inner exception stack trace — at Microsoft.SharePoint.SPListCollection.GetListByName(String strListName, Boolean bThrowException) at Company.Custom.Config..cctor() — End of inner exception stack trace — at …
…Company.Custom.Config.get_ConfigValue() at Company.Custom.Pages.Layouts.Company.Custom.YourPage.Page_Load(Object sender, EventArgs e) at Microsoft.SharePoint.WebControls.UnsecuredLayoutsPageBase.OnLoad(EventArgs e) at Microsoft.SharePoint.WebControls.LayoutsPageBase.OnLoad(EventArgs e) at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) at System.Web.UI.Page.HandleError(Exception e) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) at System.Web.UI.Page.ProcessReques… …t() at System.Web.UI.Page.ProcessRequest(HttpContext context) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Based on the logs the users have obviously problem with accessing the custom list called “Config”. At first we thought the list was deleted accidentally, or the users do not have permission on it, but after a quick check it turned out that the list is there, and the users have no problem accessing it via the web UI.
This list is used by the web application to persist specific application-wide settings as name-value pairs. A custom static class called “Config” is responsible to read up the configuration values from the SharePoint list into a static Dictionary field, and provide them to the other components of the application as static properties of the class. In the original implementation of the class the configuration values were read up from the list in the static constructor and that is without elevated permission, since (at least theoretically) all users should have at least read permissions to the list.
What’s wrong with this approach? Why can’t users that definitely do have permission to the list access it?
If there is at least a single user without permission to the list, and this user happens to be the first one that tries to access the Config object after the application pool of the web application (re)started or recycled by IIS, the static constructor must throw obviously a TypeInitializationException exception, as there is an unhandled exception in the static constructor. The real exception, that caused the problem is included in the InnerException of the TypeInitializationException exception. But why do the other users (having permissions to the list) become the same error?
The answer can be found on MSDN:
”If a static constructor throws an exception, the runtime will not invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain in which your program is running.”
In our case the application domain means the process of the IIS application pool. Although it is not documented in the article mentioned above, but based on our experience on each further access on any static methods / properties the very same exception would be thrown as the first time.
It is not something SharePoint-specific, one can have the same issue with broken SQL Server connection as well.
When you execute this code, it will output something like this:
The main points you should notice:
- There is only a single line of “Static constructor invoked”. It means, the static constructor is only invoked once.
- The main exception is always a TypeInitializationException, the “real” exception (in our case, it is an ApplicationException) is provided in the InnerException property. Based on the ULS logs above, the InnerException is logged out by SharePoint (that is a good thing), and it caused us a bit of confusion (that is not so good, of course).
- The exception thrown by accessing the static members is always the same as the first one, compare the time stamps values in the output.
How to solve the problem once we know the real reason of the issue?
As we wanted to remedy the issue as fast as possible, the very first step was to resolve the direct cause of the problem, so we granted permissions on the Config list for the few users who did not have access earlier.
For a long-term solution, I think the most important step was to refactor the Config class. The code of the static constructor was transformed to a private static method (let’s call it InitializeIfNeeded). In this method we lock the Dictionary object used to store the configuration values, to provide a kind of thread safety and support potential concurrent calls. We check next, if the configuration values were already initialized (via a static boolean field called isConfigInitialized). If they were, we exit from the InitializeIfNeeded method. If they were not, we read up the values from the SharePoint list into the Dictionary object, and set the value of the isConfigInitialized field to true. On accessing each of the static properties of the Config class representing the individual configuration values, we invoke first the InitializeIfNeeded method, to ensure the values are available. Using this simple step we can ensure, that users that do have permission on the SharePoint list can accesd the configuration values. Users without permission may have still the problem that the values cannot be read from the list, if they are the first ones to visit the pages. If they are visiting the pages after the values were already initialized (via a visit of a user with permission), they can of course access the configuration values as well.
As next step, in the InitializeIfNeeded method we embedded the code responsible for reading up the values from the SharePoint list into the Dictionary object into an elevated permission block to ensure all user (even the ones without direct permission to the list) can read the values up.
After testing the new version and deploying it into the production system, we can revoke the direct permissions from the Config list for the standard users, and let only administrators to read and change configuration value via the web UI.