2017-01-11 9 views
0

지정한 폴더 내에 새 폴더가 만들어 질 때마다 트리거되는 C# 애플릿에서 실행되는 WQLEventQuery를 만들려고합니다. 이전에 WMI를 사용했고 어떻게 작동하는지 잘 알고 있습니다. 새 파일을 특정 폴더에 추가 할 때 동일한 유형의 이벤트 쿼리를 성공적으로 만들었습니다. 이상한 부분은 디버깅에서 애플릿을 실행할 때 예외가 발생한다는 것입니다. 그러나 동일한 쿼리를 가져와 'wbemtest'유틸리티 (Windows에 내장 된 유틸리티)에서 실행하면 '잘못된 쿼리'가 throw됩니다. Within 절을 제거하면 이 발생합니다.. 그러나 C# 코드에서 WQLEventQuery 개체의 WithinInterval 속성을 설정하지 않으면 폴링 간격과 관련하여 다른 예외가 throw됩니다.WMI 잘못된 쿼리가 C#에서 작동하지만 wbemtest 유틸리티에서 작동합니다.

FolderMonitor.cs

using System; 
using System.Configuration; 
using System.Management; 
using MyProject.core.interfaces; 

namespace MyProject.monitor.WmiEventMonitors 
{ 
    public class FolderMonitor : IWQLMonitor 
    { 
     private const string _eventClassName = "__InstanceCreationEvent"; 
     private const string _isaType = "Win32_SubDirectory"; 

     private readonly IEventListenerManager _eListenerManager; 
     private readonly IFileProcessService _fileProcessService; 

     public WqlEventQuery Query { get; } 
     public string Path { get; } 

     public FolderMonitor(string path, IEventListenerManager eListenerManager, IFileProcessService fileProcessService) 
     { 
      _eListenerManager = eListenerManager; 
      _fileProcessService = fileProcessService; 

      if (string.IsNullOrEmpty(path)) 
       path = GetConfiguredDirectory(); 

      Path = path; 

      var queryParamPath = path.Replace(@"\", @"\\"); 

      //Query = new WqlEventQuery(); 
      //Query.QueryString = [email protected]"Select * From {_eventClassName} Within 1 Where TargetInstance Isa '{_isaType}' And TargetInstance.GroupComponent = 'Win32_Directory.Name={queryParamPath}'"; 

      Query = new WqlEventQuery 
      { 
       EventClassName = _eventClassName, 
       Condition = $"TargetInstance isa '{_isaType}' And TargetInstance.GroupComponent = 'Win32_Directory.Name={queryParamPath}'" 
       WithinInterval = new TimeSpan(0,5,0) 
      }; 
     } 

     public void HandleEvent(object sender, EventArrivedEventArgs e) 
     { 
      // when a new subfolder is created: 
      // 1) Log it somewhere? 
      // 2) Create a new WMI listener for that subfolder to detect file creation 
      string newDirPath = null; 
      try 
      { 
       foreach (PropertyData pd in e.NewEvent.Properties) 
       { 
        if (pd.Name != "TargetInstance") continue; 

        ManagementBaseObject mbo; 
        if ((mbo = pd.Value as ManagementBaseObject) != null) 
        { 
         using (mbo) 
         { 
          var newSubDir = mbo.Properties["PartComponent"]; 
          var newDir = newSubDir.Value as ManagementBaseObject; 
          newDirPath = $"{newDir.Properties["Drive"].Value}{newDir.Properties["Path"].Value}"; 
        } 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex.Message); 
       Console.WriteLine(ex.StackTrace); 
       throw; 
      } 

      if (!string.IsNullOrEmpty(newDirPath)) 
      { 
       var newFileMonitorEvent = new FileMonitor(newDirPath, _fileProcessService); 
       _eListenerManager.Add(newFileMonitorEvent); 
      } 
     } 


     private static string GetConfiguredDirectory() 
     { 
      return ConfigurationManager.AppSettings["Directory"].Trim(); 
     } 

    } 
} 

내 이벤트 등록 클래스

using System; 
using System.Management; 
using MyProject.monitor.WmiEventMonitors; 

namespace MyProject.monitor 
{ 
    public interface IFileMonitorEventRegistrar 
    { 
     ManagementEventWatcher RegisterEventListener(IWQLMonitor newMonitorCandidate); 
     bool UnregisterEventListener(ManagementEventWatcher listener); 
    } 

    public class FileMonitorEventRegistrar : IFileMonitorEventRegistrar 
    { 
     public ManagementEventWatcher RegisterEventListener(IWQLMonitor newMonitorCandidate) 
     { 
      var scope = WmiUtility.GetConnectionScope(); 
      ManagementEventWatcher watcher = null; 
      try 
      { 
       watcher = new ManagementEventWatcher(scope, newMonitorCandidate.Query); 
       watcher.EventArrived += new EventArrivedEventHandler(newMonitorCandidate.HandleEvent); 
       watcher.Start(); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.Message); 
       Console.WriteLine(e.StackTrace); 
       throw; 
      } 
      return watcher; 
     } 

     public bool UnregisterEventListener(ManagementEventWatcher listener) 
     { 
      listener.Stop(); 
      listener.Dispose(); 

      return true; 
     } 
    } 
} 

내 WMI 유틸리티 클래스

using System; 
using System.Management; 

namespace MyProject.monitor 
{ 
    public static class WmiUtility 
    { 
     private static ManagementScope _connectionScope; 
     private static ConnectionOptions _connectionOptions; 


     public static ManagementScope GetConnectionScope() 
     { 
      EstablishConnection(null, null, null, Environment.MachineName); 
      return _connectionScope; 
     } 


     private static ConnectionOptions SetConnectionOptions() 
     { 
      return new ConnectionOptions 
      { 
       Impersonation = ImpersonationLevel.Impersonate, 
       Authentication = AuthenticationLevel.Default, 
       EnablePrivileges = true 
      }; 
     } 


     private static ManagementScope SetConnectionScope(string machineName, ConnectionOptions options) 
     { 
      ManagementScope connectScope = new ManagementScope(); 
      connectScope.Path = new ManagementPath(@"\\" + machineName + @"\root\CIMV2"); 
      connectScope.Options = options; 

      try 
      { 
       connectScope.Connect(); 
      } 
      catch (ManagementException e) 
      { 
       Console.WriteLine(e.Message); 
       Console.WriteLine(e.StackTrace); 
       throw; 
      } 
      return connectScope; 
     } 


     private static void EstablishConnection(string userName, string password, string domain, string machineName) 
     { 
      _connectionOptions = SetConnectionOptions(); 
      if (domain != null || userName != null) 
      { 
       _connectionOptions.Username = domain + "\\" + userName; 
       _connectionOptions.Password = password; 
      } 
      _connectionScope = SetConnectionScope(machineName, _connectionOptions); 
     } 
    } 
} 

내 EventQuery 관리자 클래스

: 여기에 상황에 대한 몇 가지 코드 조각은 '\\ MonitoredDocs Win32_Directory.Name = C'

using System; 
using System.Configuration; 
using System.IO; 
using System.Linq; 
using MyProejct.monitor.WmiEventMonitors; 
using MyProject.core.interfaces; 

namespace MyProject.monitor 
{ 
    public interface IFileMonitorService : IDisposable 
    { 
     void Initialize(); 
    } 

    public class FileMonitorService : IFileMonitorService 
    { 
     private bool _disposed; 

     private readonly IEventListenerManager _eventListenerManager; 
     private readonly IFileMonitorEventRegistrar _eventRegistrar; 
     private readonly IFileProcessService _fileProcessService; 
     private string _parentDirectory; 

     public FileMonitorService(IFileMonitorEventRegistrar eventRegistrar, IFileProcessService fileProcessService) 
     { 
      _eventRegistrar = eventRegistrar; 
      _fileProcessService = fileProcessService; 
      _eventListenerManager = new EventListenerManager(_eventRegistrar); 
     } 


     public void Initialize() 
     { 
      if (string.IsNullOrEmpty(_parentDirectory)) 
       _parentDirectory = ConfigurationManager.AppSettings["SFTPDirectory"].Trim(); 

      if (!_eventListenerManager.RegisteredEvents.Any()) 
      { 
       GenerateFileEventListeners(); 
       GenerateParentFolderListener(); 
      } 
     } 

     public void GenerateFileEventListeners() 
     { 
      if (!Directory.Exists(_parentDirectory)) 
       return; 

      var foldersToMonitor = Directory.EnumerateDirectories(_parentDirectory); 

      foreach (var folderPath in foldersToMonitor) 
      { 
       // Create a listener 
       var fileMonitor = new FileMonitor(folderPath, _fileProcessService); 
       _eventListenerManager.Add(fileMonitor); 
      } 
     } 

     public void GenerateParentFolderListener() 
     { 
      var folderMonitor = new FolderMonitor(_parentDirectory, _eventListenerManager, _fileProcessService); 
      _eventListenerManager.Add(folderMonitor); 
     } 

     public virtual void Dispose(bool disposing) 
     { 
      if (!_disposed) 
      { 
       if (disposing) 
       { 
        _eventListenerManager.Dispose(); 
        _parentDirectory = null; 
       } 

       _disposed = true; 
      } 
     } 

     public void Dispose() 
     { 
      Dispose(true); 
     } 
    } 
} 

그래서 쿼리 문자열은 본질적으로 입니다 오케 스트레이터 클래스 "* __InstanceCreationEvent 1 내 위치를 TargetInstance의 ISA 'Win32_SubDirectory'그리고 TargetInstance.GroupComponent =을 선택 "

쿼리 문자열을 가져 와서 within 절을 제거하면 wbemtest가이를 유효한 WMI 쿼리로 받아들입니다. within 절이 있으면 잘못된 쿼리라고합니다. this article의 답변을 사용하고 있습니다. 이 WQL 이벤트 쿼리를 작동시키는 방법을 이해하는 데 도움이 될 것입니다.

답변

0

그래서 나는 위에 초점을 맞춘 기사를 읽고 실제로 작동하는 대체 쿼리를 발견했습니다. 쿼리 문자열은 다음과 같습니다.

선택 * From __InstanceCreationEvent 1 이내 TargetInstance Isa 'Win32_Directory'및 TargetInstance.Drive = 'C :'TargetInstance.Path = '\\ path \\ to \\ monitored \\ directory 혼동 할 수 \\ '

* 한 세부 경로 값이 코드의 관점에서 후행 "\\"

를 포함하는 것을, 내 수정 FolderMonitor.cs 클래스는 다음과 같습니다이다 : (변경 *! *! *)

public class FolderMonitor : IWQLMonitor 
    { 
     private const string _eventClassName = "__InstanceCreationEvent"; 

     *!*!*private const string _isaType = "Win32_Directory";*!*!* 

     private readonly IEventListenerManager _eListenerManager; 
     private readonly IFileProcessService _fileProcessService; 

     public WqlEventQuery Query { get; } 
     public string Path { get; } 

     public FolderMonitor(string path, IEventListenerManager eListenerManager, IFileProcessService fileProcessService) 
     { 
      _eListenerManager = eListenerManager; 
      _fileProcessService = fileProcessService; 

      if (string.IsNullOrEmpty(path)) 
       path = GetConfiguredDirectory(); 

      Path = path; 

      *!*!*var drive = Path.Substring(0, 2);*!*!* 
      *!*!*var queryPath = Path.Substring(2) + @"\";*!*!* 

      var queryParamPath = queryPath.Replace(@"\", @"\\"); 

      Query = new WqlEventQuery 
      { 
       EventClassName = _eventClassName, 

       *!*!*Condition = $"TargetInstance Isa '{_isaType}' And TargetInstance.Drive = '{drive}' And TargetInstance.Path = '{queryParamPath}'",*!*!* 

       WithinInterval = new TimeSpan(0,0,1) 
      }; 
     } 
    }