-2

I want to learn correct multithreading in C#. I want to create a programm that access multiple API's to get informations. To reduce traffic those will be saved localy and only updated after time X. Then I need to access some webpages with default http to read out the HTML to get the rest of my needed information. Just to learn it i want to get it as much parallel and non blocking as possible. I found a solution for it here: https://stackoverflow.com/a/18033198/8953694 with that i created mine. For now its just load/save API Keys from the UI but i would use that style for everything else i would do. Is that a good way to do it?

My Code:

`c#

private async void Load()
{
    try
    {
        JsonAPI jsonAPI = await Task.Run(() => UIHandler.LoadSettingsAsync());
        bapi_client_ID.Text = jsonAPI.Dienst[0].ApiKey[0].Key;
        bapi_Client_Secret.Text = jsonAPI.Dienst[0].ApiKey[1].Key;
    }
    catch (Exception error)
    {
        statusBar.Text = "Error: " + error.Message;
    }
}
private async void Save_settings_Click(object sender, RoutedEventArgs e)
{
    save_settings.IsEnabled = false;
    statusBar.Text = "Save settings...";
    try
    {
        JsonAPI jsonAPI = ConvertAPIJson();
        await Task.Run(() => UIHandler.SaveSettingsAsync(jsonAPI));
    }
    catch (Exception error)
    {
        statusBar.Text = "Error: " + error.Message;
    }
    statusBar.Text = "Settings saved!";
    save_settings.IsEnabled = true;
}
public static async Task SaveSettingsAsync(JsonAPI jsonAPI)
{
    byte[] encodedText = Encoding.Unicode.GetBytes(JsonConvert.SerializeObject(jsonAPI));

    using (FileStream fs = new FileStream(@"API.json", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
    {
        fs.SetLength(0);
        await fs.WriteAsync(encodedText, 0, encodedText.Length);
    }
}        
public static async Task<JsonAPI> LoadSettingsAsync()
{
    byte[] encodedText;

    using (FileStream fs = new FileStream(@"API.json", FileMode.OpenOrCreate, FileAccess.Read, FileShare.None))
    {
        encodedText = new byte[(int)fs.Length];
        await fs.ReadAsync(encodedText, 0, (int)fs.Length);
    }

    return JsonConvert.DeserializeObject<JsonAPI>(Encoding.Unicode.GetString(encodedText));
}

``

To change UI Elements i would do it with the progress keyword just as in the example. Are there any better ways to do it?

Niccoo
  • 11
  • 4

1 Answers1

0

Remove Task.Run wrappers, "Load" and "Save" methods are asynchronous and can be called without it.

private async void Load()
{
    var settings = await UIHandler.LoadSettingsAsync();

    bapi_client_ID.Text = settings.Dienst[0].ApiKey[0].Key;
    bapi_Client_Secret.Text = settings.Dienst[0].ApiKey[1].Key;
}

private async void Save_settings_Click(object sender, RoutedEventArgs e)
{
    statusBar.Text = "Save settings...";

    var settings = ConvertAPIJson();
    await UIHandler.SaveSettingsAsync(settings);

    statusBar.Text = "Settings saved!";
}

When accessing external resources (Web services, database, file system), asynchronous approach provides possibility to access external resources in unblocking way and within one thread.
By wrapping this kind of methods with another thread, you just wasting a thread which executing nothing, but only waiting for a response.

Task.Run Etiquette Examples: Don't Use Task.Run for the Wrong Thing

Fabio
  • 31,528
  • 4
  • 33
  • 72
  • I had this before. But as i simulated a load time e.g. a long while loop it blocks the main thread. Using a blocking call like Thread.Sleep obviusly blocked aswell – Niccoo May 12 '19 at 18:34
  • You should mention UI Framework you are using, Winforms, WPF? – Fabio May 12 '19 at 19:34
  • @Niccoo: Sounds like you simulated a synchronous blocking operation. To simulate an asynchronous operation use `await Task.Delay(...)`. – Stephen Cleary May 12 '19 at 21:23
  • Okay. But for heavy CPU workload Like many many calculations i would still use the task.run approach correct? And im useing a WPF application – Niccoo May 13 '19 at 03:46
  • If you wanna run calculations explicitly on the different thread, then yes. – Fabio May 14 '19 at 10:23