3

Recently we have been encountering the following problem in production when reading our configuration file.

Object reference not set to an instance of an object. (C:\applications\SampleWebsite\web.config line 105) at at System.Configuration.BaseConfigurationRecord.EvaluateOne(String[] keys, SectionInput input, Boolean isTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult) at System.Configuration.BaseConfigurationRecord.Evaluate(FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult, Boolean getLkg, Boolean getRuntimeObject, Object& result, Object& resultRuntimeObject) at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject) at System.Configuration.BaseConfigurationRecord.GetSection(String configKey) at System.Configuration.ConfigurationManager.GetSection(String sectionName) at SampleWebsite.Configuration.CustomConfigurationSection.get_Current() in c:\Builds\1\SampleWebsite\Sources\Source\SampleWebsite\Configuration\CustomConfigurationSection.cs:line 69 at SampleWebsite.Security.AuthorizationManager.CheckAccess(AuthorizationContext context) in c:\Builds\1\SampleWebsite\Sources\Source\SampleWebsite\Security\AuthorizationManager.cs:line 161 at System.IdentityModel.Services.ClaimsPrincipalPermission.Demand() at System.Security.PermissionSet.DemandNonCAS() at SampleWebsite.CustomController.Test() in c:\Builds\1\SampleWebsite\Sources\Source\SampleWebsite\Controllers\CustomController.cs:line 125 at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c_DisplayClass13.b_c(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)

We are using .NET 4.5 on IIS 8 on a Windows Server 2012. The issue sometimes (not always!) occurs after the recycle of the application pool. If the issue occurs, we have to stop our application pool and start our application pool. Recycling the application pool does not help, neither does restarting the website.

Nothing was changed in the configuration file. The only real difference we have noticed is that there are more requests made to the website itself.

Since we first thought it could have been a race condition, we have scheduled the application pool to recycle at a specific time when we are sure that no requests are being send to the website.

The recycle time has been chosen at a time when the applications that send requests to this site are shut down and before they are started up again.

The application pool has the following configuration options set:

  • Start Automatically: true
  • Start Mode: AlwaysRunning
  • Start application pool immediately: true

The website has the following options set:

  • Preload Enabled: true
  • Start automatically: true

Has anyone encountered this issue before?

Any help would be greatly appreciated!

EDIT:

This is basically what's in the custom config section code:

public sealed class CustomConfigurationSection : ConfigurationSection
{
    private static CustomConfigurationSection _current;

    public static CustomConfigurationSection Current
    {
        get
        {
            return _current
                ?? (_current = ConfigurationManager.GetSection(CustomSectionName) as CustomConfigurationSection);
        }
    }
}

The nullref occurs in the ConfigurationManager.GetSection() after the app pool is recycled and the _current field (a static) is nullified and needs to be read again from the config file.

stombeur
  • 2,704
  • 22
  • 45
Meertman
  • 197
  • 2
  • 13
  • 1
    http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it – Soner Gönül Apr 03 '14 at 07:32
  • 1
    What's in `CustomConfigurationSection.cs`? – CodingIntrigue Apr 03 '14 at 07:34
  • @Soner OP knows what a nullref is. We just don't know why the custom config section is null at random times. 99% of the time, the section is read correctly. 1% of the time it barfs for no apparent reason and with no changes at all in the config file – stombeur Apr 03 '14 at 07:54
  • @RGraham, see edit in the question. Is this enough info? – stombeur Apr 03 '14 at 08:08

1 Answers1

3

The null coalescing operator you are using is not thread safe. Add a locking variable to your getter:

private static CustomConfigurationSection _current;
private static readonly object _lock = new object();

public static CustomConfigurationSection Current
{
    get
    {
        lock(_lock) {
            return _current
                ?? (_current = ConfigurationManager.GetSection(CustomSectionName) as CustomConfigurationSection);
        }
    }
}

It's also possible that the ConfigurationManager isn't returning the expected value shortly after the recycle of the application pool (I can't see where CustomSectionName is defined). It might be worth adding a check here to ensure that you are actually returning the expected section.

It may also be worth setting the static property inside the constructor of the CustomConfigurationSection:

public sealed class CustomConfigurationSection : ConfigurationSection
{
    public CustomConfigurationSection() {
        Current = CurrentConfiguration.GetSection(CustomSectionName);
    }

    public static CustomConfigurationSection Current { get; private set; }
}
Community
  • 1
  • 1
CodingIntrigue
  • 75,930
  • 30
  • 170
  • 176
  • +1 for the _lock. That was already in dev branch, but not yet in production. We'll rewrite the getter to be more verbose and check and log the contents of the custom section before casting. Thx! We'll run this for a couple of days to see what gives. It's very hard to reproduce, so will take a while to confirm if this is the solution. – stombeur Apr 03 '14 at 08:23
  • Actually, the check to ensure we are getting the right section may be irrelevant. The exception occurs in System.Configuration.BaseConfigurationRecord.EvaluateOne(String[] keys, SectionInput input, Boolean isTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult), so in some deeper part of the configuration manager logic to read sections. – stombeur Apr 03 '14 at 08:41
  • @StephaneT That's true, in that case it may be that you need to change the property to a basic `Current {get;set;}` and set the static value in the constructor. That way, you can access `CurrentConfiguration` rather than the static `ConfigurationManager` instance. – CodingIntrigue Apr 03 '14 at 08:50
  • I'm not sure I understand what you mean with `CurrentConfiguration` – stombeur Apr 03 '14 at 08:57
  • @RGraham Is the `CurrentConfiguration` more safe to use than the `ConfigurationManager`? – Meertman Apr 03 '14 at 08:59
  • @Meertman Not "more safe" as such, it's just that when implementing a custom configuration section, it would make more sense to use the *context* rather than assume that the static instance of `ConfigurationManager` is ready when you expect it - especially immediately after an application pool refresh – CodingIntrigue Apr 03 '14 at 09:00
  • @StephaneT Updated answer with an example – CodingIntrigue Apr 03 '14 at 09:01
  • @RGraham Good advice, one question though... shouldn't the constructor of the CustomConfigurationSection be static? – Meertman Apr 03 '14 at 09:05
  • @RGraham You can, however you would not be able to access the `CurrentConfiguration`. In your code sample, the use of the static current property outside of the `CustomConfigurationSection` could be a problem. Since you can access the `Current` variable without creating an instance of the `CustomConfigurationSection` it will always be null, won't it? – Meertman Apr 03 '14 at 09:09
  • @Meertman Correct, and that's the point here. If the constructor is never called, there is no instance and `Current` should indeed return null. It's a Singleton. – CodingIntrigue Apr 03 '14 at 09:15
  • the default ctor will be called from the runtime somewhere when initializing the configuration? – stombeur Apr 03 '14 at 09:17
  • @RGraham, could we also use `ConfigurationManager.RefreshSection()` when it is null so the next request will read it again from disk? – stombeur Apr 03 '14 at 09:18
  • @StephaneT It might not matter if the `ConfigurationManager` is empty, you would probably just end up with the same exception. A constructor of some sort must be called by the manager – CodingIntrigue Apr 03 '14 at 09:22
  • @RGraham we've had the lock and some other minor changes in production for a while and the problem has not presented itself anymore. We're still trying to reproduce, but we're pretty confident it was a multi-threading issue. – stombeur Apr 24 '14 at 07:52