I read a lot of posts about async methods, but still... I'm a little confused about this. So maybe someone can help me with my case. Right now my code doesn't throw any error, but I know that my code is not good, cause I use async void and I can't wait for all my task to be completed.
So, can someone please help me edit this code:
In my form class, I create Relation:
Relation rel = new Relation(cb_MachineToConnect.Text);
In Relation class:
public Relation(string machineAddress)
{
isAsctive = true;
idCount++;
relationID = idCount;
machine = new Machine(machineAddress);
//I'm using WMI for gettig data from remote machine
scope = new ManagementScope(string.Format("\\\\{0}\\root\\cimv2", machineAddress));
scope.Options.Timeout = TimeSpan.FromSeconds(timeOut);
//In this method, I need run async part of code - WMI selects
LoadMachineData();
}
LoadMachineData methode code:
private async void LoadMachineData()
{
try
{
scope.Connect();
try
{
//List<Task> taskList = new List<Task>();
foreach (KeyValuePair<SelectQueryName, SelectQuery> select in SelectQueryes)
{
//And this is it.. I need to run this methods async for better performance. SelectFromWMI is in Relation class and SetWMIproiperties is in Machine class
await Task.Run(() => machine.SetWMIProperties(select.Key, SelectFromWMI(select.Value, scope)));
//taskList.Add(t);
//machine.SetWMIProperties(select.Key, SelectFromWMI(select.Value, scope));
}
//I also want to wait for all created Tasks completion, but with this code it is not possible
//Task.WaitAll(taskList.ToArray());
}
catch (Exception ex)
{
EventNotifier.LogOnScreen(string.Format("{0}, viz: {1}", ErrorList.GetEIbyID(15).definition, ex.Message));
EventNotifier.Log(ex, ErrorList.GetEIbyID(15));
}
}
catch (Exception ex)
{
EventNotifier.LogOnScreen(string.Format("{0}, viz: {1}", ErrorList.GetEIbyID(16).definition, ex.Message));
EventNotifier.Log(ex, ErrorList.GetEIbyID(17));
}
}
SetWMIProperties(...) in Machine class:
public void SetWMIProperties(SelectQueryName queryName, List<Dictionary<string, string>> propertiesData)
{
foreach (Dictionary<string, string> result in propertiesData)
{
switch (queryName)
{
case SelectQueryName.DiskModel:
disks.Add(result["Model"]);
break;
case SelectQueryName.Drives:
drives.Add(new Drive { Name = result["Name"], FreeSpace = Convert.ToInt64(result["FreeSpace"]), Size = Convert.ToInt64(result["Size"]) });
break;
case SelectQueryName.OS:
operatingSystem = new OS { BuildNumber = result["BuildNumber"], ProductName = result["Caption"], BitVersion = (result["OSArchitecture"].Contains(((int)OSBitVersion.Win32).ToString())) ? OSBitVersion.Win32 : OSBitVersion.Win64 };
break;
case SelectQueryName.Processor:
processor = result["Name"];
break;
case SelectQueryName.RAM:
ram = new RAM { TotalVisibleMemorySize = Convert.ToInt64(result["TotalVisibleMemorySize"]), FreePhysicalMemory = Convert.ToInt64(result["FreePhysicalMemory"]) };
break;
}
}
}
And the WMI select method in Relation class (in fact, this method should to be truly async, cause WMI select can sometimes be really slow):
private static List<Dictionary<string, string>> SelectFromWMI(SelectQuery select, ManagementScope wmiScope)
{
List<Dictionary<string, string>> result = new List<Dictionary<string, string>>();
ManagementObjectSearcher searcher = new ManagementObjectSearcher(wmiScope, select);
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;
}
To await all your tasks you can use
Task.WhenAll()
:To wait for completion of
LoadMachineData()
you can change it signature toasync Task
and call asLoadMachineData().Wait()
. Is that what you need?