4

FileSystemWatcher를 사용하여 app.config 파일의 변경 사항을 모니터링하고 있습니다. 또한 config 파일에 기록합니다.app.config의 변경 내용을 읽고 app.config 실시간으로 쓰기 위해 FileSystemMonitoring 사용

에서는 MyApplication는 주요 프로젝트 및 DataCache가에서는 MyApplication에서 참조 CLA를 라이브러리입니다 :

여기 내 코드입니다. 콘솔 입력에서 이름에 대한 모든 변경 사항이있는 경우

using System; 
namespace DataCache 
{ 
    public sealed class DataConfigSection : System.Configuration.ConfigurationSection 
    { 
     public static System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(
     System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(DataConfigSection)).Location), "MyApplication.exe")); 

    // Create a "name" element. 
    [System.Configuration.ConfigurationProperty("name")] 
    public NameElement Name 
    { 
     get 
     { 
      return (NameElement)this["name"]; 
     } 
     set 
     { 
      this["name"] = value; 
     } 
    } 

    // Define the "name" element 
    // with firstName, secondName attributes. 
    public class NameElement : System.Configuration.ConfigurationElement 
    { 
     [System.Configuration.ConfigurationProperty("firstName", DefaultValue = "abcd", IsRequired = true)] 
     public String FirstName 
     { 
      get 
      { 
       return (String)this["firstName"]; 
      } 
      set 
      { 
       this["firstName"] = value; 
      } 
     } 

     [System.Configuration.ConfigurationProperty("lastName", DefaultValue = "xyz", IsRequired = true)] 
     public String LastName 
     { 
      get 
      { 
       return (String)this["lastName"]; 
      } 
      set 
      { 
       this["lastName"] = value; 
      } 
     } 
    } 
    } 
} 


namespace DataCache 
{ 
    public class Section1Data 
    { 
     public static volatile DataConfigSection configSection1; 
     private static object syncRoot = new System.Object(); 

    public const string Section1ConfigSectionName = "MySectionGroup/Section1"; 

    private Section1Data() { } 

    public static DataConfigSection ConfigSection1 
    { 
     get 
     { 
      lock (syncRoot) 
      { 
       if (configSection1 == null) 
       { 
        DataConfigSection.config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(DataConfigSection)).Location), "MyApplication.exe")); 
        configSection1 = (DataConfigSection)DataConfigSection.config.GetSection(Section1ConfigSectionName);     
       } 
      } 
      return configSection1; 
     } 
    } 
    public static string FirstNameString 
    { 
     get 
     { 
      return ConfigSection1.Name.FirstName.ToString(); 
     } 
     set 
     { 
      ConfigSection1.Name.FirstName = value; 
      DataConfigSection.config.Save(); 
     } 
    } 
    public static string LastNameString 
    { 
     get 
     { 
      return ConfigSection1.Name.LastName.ToString(); 
     } 
     set 
     { 
      ConfigSection1.Name.LastName = value; 
      DataConfigSection.config.Save(); 
     } 
    } 
    } 
} 

문제는, FileChanged 번 호출되는 이후의 변화가 발생하지 않는다 : 여기

using System; 
using System.Threading; 
using System.IO; 
namespace MyApplication 
{ 

    public class Program 
    { 
    public static string rootFolderPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); 
    public static string configFilePath = Path.Combine(rootFolderPath, "MyApplication.exe.config");static void Main(string[] args) 
    { 
     //First Time initializing the config file. 
     ConfigFileMonitor.SetConfigFileAtRuntime(configFilePath); 

     //Initializing the config file monitor on a separate thread. 
     Thread monitorThread = new Thread(ConfigFileMonitor.BeginConfigFilesMonitor); 
     monitorThread.Start(); 

     WriteToConfigFile(); 

    } 

    static void WriteToConfigFile() 
    { 
     Console.WriteLine(String.Format("Hello {0} {1}", DataCache.Section1Data.FirstNameString, DataCache.Section1Data.LastNameString)); 

     string _firstName, _lastName = string.Empty; 
     do 
     { 
      Console.WriteLine(""); 
      Console.Write("First Name : "); 
      _firstName = Console.ReadLine(); 

      Console.Write("Last Name : "); 
      _lastName = Console.ReadLine(); 

      if(_firstName.Length>0) 
       DataCache.Section1Data.FirstNameString = _firstName; 

      if(_lastName.Length>0) 
       DataCache.Section1Data.LastNameString = _lastName; 

      Console.WriteLine(String.Format("Hello {0} {1}", DataCache.Section1Data.FirstNameString, DataCache.Section1Data.LastNameString)); 
     } 
     while (true); 
    } 
    } 
} 


using System; 
using System.IO; 

namespace MyApplication 
{ 
    /// <summary> 
    /// Monitors for any change in the app.config file 
    /// </summary> 
    public class ConfigFileMonitor 
    { 
     private static FileSystemWatcher _watcher; 
     private static string _configFilePath = String.Empty; 
     private static string _configFileName = String.Empty; 

     /// <summary> 
    /// Texts the files surveillance. 
    /// </summary> 
    public static void BeginConfigFilesMonitor() 
    { 
     try 
     { 
      string fileToMonitor = Program.configFilePath; 
      if (fileToMonitor.Length == 0) 
       Console.WriteLine("Incorrect config file specified to watch"); 
      else 
      { 
       _configFileName = Path.GetFileName(fileToMonitor); 
       _configFilePath = fileToMonitor.Substring(0, fileToMonitor.IndexOf(_configFileName)); 
      } 
      // Use FileWatcher to check and update only modified text files. 
      WatchConfigFiles(_configFilePath, _configFileName); 
     } 
     catch (Exception e1) 
     { 
      Console.WriteLine(e1.Message); 
     } 
    } 

    /// <summary> 
    /// Watches the files. 
    /// </summary> 
    /// <param name="targetDir">The target dir.</param> 
    /// <param name="filteredBy">The filtered by.</param> 
    static void WatchConfigFiles(string targetDir, string filteredBy) 
    { 
     try 
     { 
      _watcher = new FileSystemWatcher(); 
      _watcher.Path = targetDir; 
      _watcher.Filter = filteredBy; 
      _watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite; 
      _watcher.EnableRaisingEvents = true; 

      _watcher.Changed += new FileSystemEventHandler(FileChanged); 
      _watcher.WaitForChanged(WatcherChangeTypes.Changed); 
     } 
     catch (Exception e1) 
     { 
      Console.WriteLine(e1.Message); 
     } 
    } 


    /// <summary> 
    /// Handles the Changed event of the File control. 
    /// </summary> 
    /// <param name="sender">The source of the event.</param> 
    /// <param name="e">The <see cref="System.IO.FileSystemEventArgs"/> instance containing the event data.</param> 
    protected static void FileChanged(object sender, FileSystemEventArgs e) 
    { 
     try 
     { 
      _watcher.EnableRaisingEvents = false; 

      string filechange = e.FullPath; 

      Console.WriteLine("Configuration File: " + filechange + "changed"); 

      //Since the file is changed - We have reload the configuration settings again. 
      SetConfigFileAtRuntime(Path.Combine(Program.rootFolderPath, "MyApplication.exe.config")); 

      Console.WriteLine(String.Format("New Name : {0} {1}", DataCache.Section1Data.FirstNameString, DataCache.Section1Data.LastNameString)); 

     _watcher.EnableRaisingEvents = true; 
     } 
     catch (Exception e1) 
     { 
      Console.WriteLine(e1.Message); 
     } 
    } 

    /// <summary> 
    /// Sets the config file at runtime. 
    /// </summary> 
    /// <param name="configFilePath"></param> 
    public static void SetConfigFileAtRuntime(string configFilePath) 
    { 
     string runtimeconfigfile; 
     try 
     { 
      if (configFilePath.Length == 0) 
       Console.WriteLine("Please specify a config file to read from "); 
      else 
      { 
       runtimeconfigfile = configFilePath; 
       _configFileName = Path.GetFileName(configFilePath); 
       _configFilePath = configFilePath.Substring(0, configFilePath.IndexOf(_configFileName)); 
      } 

      // Specify config settings at runtime. 
      //System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); 
      DataCache.DataConfigSection.config = System.Configuration.ConfigurationManager.OpenExeConfiguration(configFilePath); 
      //Similarly you can apply for other sections like SMTP/System.Net/System.Web etc.. 
      //But you have to set the File Path for each of these 
      //config.AppSettings.File = runtimeconfigfile; 

      //This doesn't actually going to overwrite you Exe App.Config file. 
      //Just refreshing the content in the memory. 
      DataCache.DataConfigSection.config.Save(System.Configuration.ConfigurationSaveMode.Modified); 

      //Refreshing Config Section 
      //ConfigurationManager.RefreshSection("appSettings"); 
      System.Configuration.ConfigurationManager.RefreshSection("MySectionGroup/Section1");     

      DataCache.Section1Data.configSection1 = null; 
     } 
     catch (Exception e1) 
     { 
      Console.WriteLine(e1.Message); 
     } 
    } 
} 
} 

<?xml version="1.0"?> 
<configuration> 
    <configSections> 
    <sectionGroup name="MySectionGroup"> 
     <section name="Section1" type="DataCache.DataConfigSection, DataCache"  allowLocation="false" allowDefinition="Everywhere"/> 
     <section name="Section2" type="DataCache.DataConfigSection, DataCache"  allowLocation="false" allowDefinition="Everywhere"/> 
    </sectionGroup> 
    </configSections> 
    <MySectionGroup> 
    <Section1> 
     <name 
     firstName ="Pierce" 
     lastName ="Brosnan" 
     /> 
    </Section1> 
    </MySectionGroup> 

<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> 
</startup> 

</configuration> 

는 DataCache의 클래스입니다. 또한 설정 파일을 수동으로 변경하면 콘솔에서 변경 될 때까지 계속 작동하고 이벤트는 계속 실행됩니다.

왜 이것이 이상한 행동인지 잘 모르겠습니다. 누구든지 나를 도울 수 있습니까?

덕분에, 모니카

+0

라인 _watcher.EnableRaisingEvents = false ( FileChanged 메소드의 끝 부분)이 맞습니까? 대신 EnableRaisingEvents를 true로 설정해야합니다. – Vagaus

+0

네가 맞습니다. 그것은 오타였습니다. 위의 게시물에서 같은 것을 편집했습니다. 그러나 문제는 동일하게 유지됩니다 : ( – Monica

답변

0

당신은 매우 복잡한 코드가 있습니다. watcher에 대한 내 코드는 약 10 행입니다.

워처 초기화를 다른 스레드로 오프로드 할 필요가 없습니다. 메인 스레드에서 초기화하십시오. 워처는 백그라운드 스레드의 파일을 감시하고 변경이 발생하면 이벤트를 발생시켜 WaitForChanged() 메소드를 호출 할 필요가 없습니다.

나는 내 작업 코드를 확인하고 너와 비교했는데 단 두 가지 차이점은 다음과 같습니다. 1. 내 필터는 다음과 같습니다. NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName 2. WaitForChanged() 메서드를 호출하지 않습니다. 3. watcher와 상호 작용하는 모든 메서드에 [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]이 적용되었습니다.

또한 감시중인 파일이 시스템 디렉토리 중 하나에 있지 않은지 확인하십시오. 감시자가 해당 파일과 제대로 작동하지 않습니다. 나는 C :에서 파일을 보려고했기 때문에 반나절 동안 내 머리를 벽에 두드렸다.

+0

안녕 Zvonko 당신이 코드를 공유하시기 바랍니다 수 있습니다. – Monica

1

짧은 버전은 다음과 같습니다 그러나

this.Watcher = new FileSystemWatcher(); 
this.Watcher.Path = this.Dir; 
this.Watcher.Filter = this.File; 
this.Watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; 
this.Watcher.EnableRaisingEvents = true; 
this.Watcher.Changed += this.OnFileChange; 

, 여기에 몇 가지 추가 처리 (그냥 파일을 읽는 외에)이 요구되는 라이브 소스로부터 취출, 좀 더 복잡한 (못생긴) 샘플입니다 .

public partial class FileModule 
{ 
    private ConcurrentDictionary<string, InputFileInfo> inputFileList = new ConcurrentDictionary<string, InputFileInfo>(); 

    public FileModule() 
    { 
     this.InitializeInputFileWatchers(); 
    } 

    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] 
    public void EnableOrDisableRaisingEventsForFileWatchers(bool enable) 
    { 
     foreach (var el in this.inputFileList) 
     { 
      el.Value.Watcher.EnableRaisingEvents = enable; 
     } 
    } 

    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] 
    private void InitializeInputFileWatchers() 
    { 
     for (int i = 0; i < this.InputFiles.Count; i++) 
     { 
      if (File.Exists(this.InputFiles[i])) 
      { 
       InputFileInfo info = new InputFileInfo(); 
       info.Fullpath = ((FileModuleSettings)this.Settings).InputFiles[i]; 
       info.Watcher.Changed += this.OnFileChange; 

       this.inputFileList.AddOrUpdate(info.Fullpath, info, (e, v) => { return info; }); 
      } 
     } 
    } 

    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] 
    private void OnFileChange(object source, FileSystemEventArgs e) 
    { 
     InputFileInfo info; 
     if (this.inputFileList.TryGetValue(e.FullPath, out info)) 
     { 
      DateTime lastWriteTime = System.IO.File.GetLastWriteTime(e.FullPath); 
      if (info.LastHandledChange != lastWriteTime) 
      { 
       TimeSpan span = lastWriteTime.Subtract(info.LastHandledChange); 
       if (span.Days == 0 && span.Hours == 0 && span.Minutes == 0 && span.Seconds == 0 && span.TotalMilliseconds < this.MinimumFileChangePeriod) 
       { 
        // Event ignored due to required minimum file change period; 
       } 
       else 
       { 
        info.LastHandledChange = lastWriteTime; 
        this.inputFileList.AddOrUpdate(e.FullPath, info, (a, v) => { return info; }); 

        lock (this.readLockerObject) 
        { 
         this.ReadFile(e.FullPath); 
        } 
       } 
      } 
     } 
    } 

    private bool ReadFile(string filepath, int count, bool directReading) 
    { 
     StreamReader sr = this.OpenStreamReader(file); 

     if (sr != null) 
     { 
      string line; 
      string[] split; 
      int signalId; 
      double value; 

      while ((line = sr.ReadLine()) != null) 
      { 
       // do sth. with line 
      } 
     } 
    } 
} 

internal class InputFileInfo : IDisposable 
{ 
    public string Dir { get; private set; } 

    public string File { get; private set; } 

    public FileSystemWatcher Watcher { get; private set; } 

    public DateTime LastHandledChange { get; set; } 

    private string fullpath; 

    public string Fullpath 
    { 
     get 
     { 
      return this.fullpath; 
     } 

     set 
     { 
      this.fullpath = BaseHelper.GetFullFilePath(value); 
      this.Dir = Directory.GetParent(this.fullpath).ToString(); 
      this.File = this.fullpath.Replace(this.Dir + "\\", string.Empty); 
      this.Watcher = new FileSystemWatcher(); 
      this.Watcher.Path = this.Dir; 
      this.Watcher.Filter = this.File; 
      this.Watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; 
      this.Watcher.EnableRaisingEvents = true; 
     } 
    } 

    public void Dispose() 
    { 
     if (this.Watcher != null) 
     { 
      this.Watcher.Dispose(); 
      this.Watcher = null; 
     } 
    } 
} 
관련 문제