Skip to content

Unhandled exception from FileConfigurationProvider when re-loading a locked file #113964

@znakeeye

Description

@znakeeye

Description

Verified in .NET 8. In our application, we have an intermittent crash where FileConfigurationProvider throws an IOException when reloading the configuration file. This is easily reproducible by locking the file immediately after saving it, commonly performed by Antivirus software.

E.g.: You will not be able to catch the exception using LoadException:

source.ReloadOnChange = true;
source.ReloadDelay = 10000; // Give us some time to lock the file from some other process...
source.OnLoadException = OnLoadException; // NOT called

Please have a look at FileConfigurationProvider.cs(96). The mistake is obvious. Opening of the stream should be inside the try block!

using Stream stream = OpenRead(file); // Outside try block! 
try
{
    Load(stream);
}

Exception details

System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. (One or more errors occurred. (The process cannot access the file 'C:\Foo\settings.json' because it is being used by another process.))
 ---> System.AggregateException: One or more errors occurred. (The process cannot access the file 'C:\Foo\settings.json' because it is being used by another process.)
 
 ---> System.IO.IOException: The process cannot access the file 'C:\Foo\settings.json' because it is being used by another process.
 
   at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
 
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
 
   at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
 
   at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
 
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
 
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
 
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.<Load>g__OpenRead|6_0(IFileInfo fileInfo)
 
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load(Boolean reload)
 
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.<.ctor>b__1_1()
 
   at Microsoft.Extensions.Primitives.ChangeToken.<>c.<OnChange>b__0_0(Action callback)
 
   at Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration`1.OnChangeTokenFired()
 
   at Microsoft.Extensions.Primitives.ChangeToken.ChangeTokenRegistration`1.<>c.<RegisterChangeTokenCallback>b__7_0(Object s)
 
   at System.Threading.CancellationTokenSource.Invoke(Delegate d, Object state, CancellationTokenSource source)
 
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
 
   --- End of inner exception stack trace ---
 
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
 
   at Microsoft.Extensions.FileProviders.Physical.PhysicalFilesWatcher.<>c.<.cctor>b__43_0(Object state)
 
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
 
--- End of stack trace from previous location ---
 
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
 
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
 
   --- End of inner exception stack trace ---

Reproduction Steps

Run attached sample project.

FileConfigurationProviderCrash.zip

Expected behavior

The attached sample project should not throw an IOException.

Actual behavior

IOException is unhandled even though we tell the FileConfigurationSource to ignore exceptions.

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions