Search code examples
c#.netfilesystemwatcherconfigurationmanager

ConfigurationManager.OpenMappedExeConfiguration "because it is being used by another process"


I'd like to re-read the MySolution.main.config (my app.config) thanks FileSystemWatcher when users modify it. I built a wrapper called FileWatcher.

Catching OnChanged event with this piece of code

    var map = new ExeConfigurationFileMap { ExeConfigFilename = _appConfigFilePath };
    var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);

raises this exception

System.Configuration.ConfigurationErrorsException HResult=0x80131902 Message=An error occurred loading a configuration file: The process cannot access the file 'C:\Source\Solutions\MySolution_1.2.3\MySolution\bin\Debug\MySolution.main.config' because it is being used by another process. (C:\Source\Solutions\MySolution_1.2.3\MySolution\bin\Debug\MySolution.main.config) Source=System.Configuration.ConfigurationManager StackTrace: at System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean ignoreLocal) in //src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ConfigurationSchemaErrors.cs:line 71 at System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors(ConfigurationSchemaErrors schemaErrors) in //src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/BaseConfigurationRecord.cs:line 3634 at System.Configuration.Configuration..ctor(String locationSubPath, Type typeConfigHost, Object[] hostInitConfigurationParams) in //src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/Configuration.cs:line 75 at System.Configuration.ClientConfigurationHost.OpenExeConfiguration(ConfigurationFileMap fileMap, Boolean isMachine, ConfigurationUserLevel userLevel, String exePath) in //src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ClientConfigurationHost.cs:line 485 at System.Configuration.ConfigurationManager.OpenExeConfigurationImpl(ConfigurationFileMap fileMap, Boolean isMachine, ConfigurationUserLevel userLevel, String exePath, Boolean preLoad) in //src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ConfigurationManager.cs:line 214 at System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap, ConfigurationUserLevel userLevel) in //src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ConfigurationManager.cs:line 192 at Siav.MySolution.Log.ConfigurationUtil.FileWatcher.OnChanged(Object sender, FileSystemEventArgs e) in C:\Source\Solutions\MySolution_1.2.3\Siav.MySolution.Log\ConfigurationUtil\FileWatcher.cs:line 60 at System.IO.FileSystemWatcher.OnChanged(FileSystemEventArgs e) in f:\dd\NDP\fx\src\services\io\system\io\FileSystemWatcher.cs:line 822 at System.IO.FileSystemWatcher.NotifyFileSystemEventArgs(Int32 action, String name) in f:\dd\NDP\fx\src\services\io\system\io\FileSystemWatcher.cs:line 773
at System.IO.FileSystemWatcher.CompletionStatusChanged(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* overlappedPointer) in f:\dd\NDP\fx\src\services\io\system\io\FileSystemWatcher.cs:line 594
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP) in f:\dd\ndp\clr\src\BCL\system\threading\overlapped.cs:line 121

This exception was originally thrown at this call stack: System.IO.__Error.WinIOError(int, string) in __error.cs System.IO.FileStream.Init(string, System.IO.FileMode, System.IO.FileAccess, int, bool, System.IO.FileShare, int, System.IO.FileOptions, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES, string, bool, bool, bool) in filestream.cs System.IO.FileStream.FileStream(string, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare) in filestream.cs System.Configuration.Internal.InternalConfigHost.StaticOpenStreamForRead(string) in InternalConfigHost.cs System.Configuration.Internal.InternalConfigHost.System.Configuration.Internal.IInternalConfigHost.OpenStreamForRead(string) in InternalConfigHost.cs System.Configuration.ClientConfigurationHost.OpenStreamForRead(string) in ClientConfigurationHost.cs System.Configuration.UpdateConfigHost.OpenStreamForRead(string) in UpdateConfigHost.cs System.Configuration.ImplicitMachineConfigHost.OpenStreamForRead(string) in ImplicitMachineConfigHost.cs System.Configuration.BaseConfigurationRecord.InitConfigFromFile() in BaseConfigurationRecord.cs

Inner Exception 1: IOException: The process cannot access the file 'C:\Source\Solutions\MySolution_1.2.3\MySolution\bin\Debug\MySolution.main.config' because it is being used by another process.

I tried with a simple lock, it doesn't work.

This is the constructor of my wrapper

    public FileWatcher(string appConfigFilePath)
    {
        _appConfigFilePath = appConfigFilePath;


        _lastRead = DateTime.MinValue;

        var watcher = new FileSystemWatcher(Path.GetDirectoryName(_appConfigFilePath))
        {
            Filter = Path.GetFileName(_appConfigFilePath),
            NotifyFilter = NotifyFilters.LastWrite,

            EnableRaisingEvents = true
        };

        watcher.Changed += OnChanged;
        watcher.Error += OnError;
    }

Any suggestions?

Thanks


Solution

  • I had to manage some retry to access the file as log4net does. I suggest to you to do the same (log4net source is available on github)