지정한 폴더 내에 새 폴더가 만들어 질 때마다 트리거되는 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 이벤트 쿼리를 작동시키는 방법을 이해하는 데 도움이 될 것입니다.