Я просто создаю приложение Form для управления удаленными рабочими станциями и серверами в сети нашей компании, и мне нужно создать функцию «Ожидание перезагрузки удаленного компьютера».Эта функция в порядке, но мне нужно, чтобы она работала асинхронно, и есть моя проблема ... Функция сначала проверяет состояние онлайн / офлайн, чтобы определить перезапуск, а затем проверяет новое значение LastBootUpTime удаленного компьютера, чтобы убедиться, что он действительно перезапущен.и не только проблема сети.Когда я запускаю эту проверку асинхронно, ManagementObjectSearcher вызывает взаимоблокировку при использовании его метода .Get ().Та же проблема у меня возникает, когда я вместо этого использую PerformanceCounter.
Для этого есть 3 основных объекта: 1) Класс формы 2) Класс отношений (принадлежит Форме) 3) Класс RestartChecker (принадлежит Владельцам)
Когда RestartChecker получает информацию о перезапуске, отправляет это информационное событие в Relation.Relation использует свое собственное событие, чтобы отправить его на значок формы и изменения формы в пользовательском интерфейсе.
Вот мой код (важные части) из RestartChecker:
Этот метод находится в классе Relation и запускаетRestartChecker.Этот метод Relation вызывается из класса Form.
public void StartRestartMonitoring()
{
restartChecker = new RestartChecker(machine.Name, machine.OperatingSystem.lastBootUpTime.Value, wmiSuccess);
//WasRestarted property calls event on value change to true. That event change icons on Form
restartChecker.RestartWasMade += new Action(() => { WasRestarted = true; });
restartChecker.Start();
}
Этот метод запускает проверку функции перезапуска
Task checker;
CancellationTokenSource tokenSource;
public void Start()
{
tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
checker = CheckActionAsync(token);
running = true;
}
Это более важная часть => Метод задачи, который должен выполняться асинхронно
private async Task CheckActionAsync(CancellationToken ct)
{
bool isOnline = await RemoteTask.PingAsync(target, PING_TIMEOUT_SECONDS);
int onlineState = (isOnline) ? 0 : 1;
try
{
lastKnownBootUpTime = (isOnline) ? (GetLastBootUpTime(target, useWMI) ?? lastKnownBootUpTime) : lastKnownBootUpTime;
}
catch (Exception ex)
{
//Logs to File
EventNotifier.Log(ex,....);
}
//This part looks OK...
while (onlineState < 2)
{
if (ct.IsCancellationRequested) { return; }
bool actualOnlineState = await RemoteTask.PingAsync(target, PING_TIMEOUT_SECONDS);
onlineState += (actualOnlineState == isOnline) ? 0 : 1;
await Task.Delay(CHECK_INTERVAL);
}
while (!ct.IsCancellationRequested)
{
if (ct.IsCancellationRequested) { return; }
//Here, until I get properly value for LastBootUpTime of remote machine, I'm still trying again and again (beacause first try is cannot be OK => machine is Online, but services for WMI is not ready yet, so there is exception on first try)
while (newBootUpTime == null)
{
try
{
newBootUpTime = GetLastBootUpTime(target, useWMI);
}
catch (Exception ex)
{
//Some reactions to exception including logging to File
}
await Task.Delay(INTERVAL);
}
//This part looks ok too..
newBootUpTime = newBootUpTime.Value.AddTicks(-newBootUpTime.Value.Ticks % TimeSpan.TicksPerSecond);
lastKnownBootUpTime = lastKnownBootUpTime.Value.AddTicks(-lastKnownBootUpTime.Value.Ticks % TimeSpan.TicksPerSecond);
if (newBootUpTime.Value > lastKnownBootUpTime.Value)
{
RestartWasMade?.Invoke();
return;
}
await Task.Delay(CHECK_INTERVAL);
}
}
Метод GetLastBoostUpTime
private static DateTime? GetLastBootUpTime(string target, bool useWMI)
{
DateTime? lastBootUpTime = null;
if (useWMI)
{
//wmiBootUpTime is SelectQuery
string dateInString = RemoteTask.SelectStringsFromWMI(wmiBootUpTime, new ManagementScope(string.Format("\\\\{0}\\root\\cimv2", target))).First()[wmiBootUpTime.SelectedProperties[0].ToString()];
lastBootUpTime = (string.IsNullOrEmpty(dateInString)) ? null : (DateTime?)ManagementDateTimeConverter.ToDateTime(dateInString);
}
else
{
TimeSpan? osRunningTime = RemoteTask.GetUpTime(target);
lastBootUpTime = (osRunningTime == null) ? null : (DateTime?)DateTime.Now.Subtract(osRunningTime.Value);
}
return lastBootUpTime;
}
Метод WMI, используемый для получения данных:
public static List<Dictionary<string, string>> SelectStringsFromWMI(SelectQuery select, ManagementScope wmiScope)
{
List<Dictionary<string, string>> result = new List<Dictionary<string, string>>();
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(wmiScope, select))
{
//This line is deadlock-maker... Because remote machine services is not ready yet, searcher.Get() is trying
//until reach it's timeout (by default it is 30s) and that's my deadlock. For the time of running searcher.Get()
//there is 30s deadlock. Where is the mistake I've made? I supposed that this can not confront my UI thread
using (ManagementObjectCollection objectCollection = searcher.Get())
{
foreach (ManagementObject managementObject in objectCollection)
{
result.Add(new Dictionary<string, string>());
foreach (PropertyData property in managementObject.Properties)
{
result.Last().Add(property.Name, property.Value?.ToString());
}
}
return result;
}
}
}
Метод PerformanceCounte, используемый для получения данных:
public static TimeSpan? GetUpTime(string remoteMachine = null)
{
try
{
using (PerformanceCounter upTime = (string.IsNullOrWhiteSpace(remoteMachine))
? new PerformanceCounter("System", "System Up Time")
: new PerformanceCounter("System", "System Up Time", null, remoteMachine))
{
upTime.NextValue();
return TimeSpan.FromSeconds(upTime.NextValue());
}
}
catch
{
return null;
}
}
метод асинхронного пинга
public async static Task<bool> PingAsync(string target, int pingTimeOut)
{
bool result = false;
Exception error = null;
using (Ping pinger = new Ping())
{
try
{
PingReply replay = await pinger.SendPingAsync(target, pingTimeOut * 1000);
result = (replay.Status == IPStatus.Success) ? true : false;
}
catch (Exception ex)
{
error = ex;
}
}
if (error != null) { throw error; }
return result;
}