1

I created a custom control to display an image. The image displayed must be loaded from a website url. I decided to use Tasks to perform the action asynchronously. This is because many images will be loaded during the operation of my program.

public Image Image { 
    get => image;
    set {
        image = value;
        Refresh();
    }
}
private Image image;

public async void LoadImageAsync(string url)
{
    Image = await GetImageAsync(url);
}

private async Task<Image> GetImageAsync(string url)
{
    HttpWebRequest request = WebRequest.CreateHttp(url);
    var response = await request.GetResponseAsync();
    using (var stream = response.GetResponseStream()) {
        return Image.FromStream(stream);
    }
}

The code above is my current setup. Is this the correct way to use Tasks?

I come from JS and Promises so I've taken my knowledge from there. I tested the method and it appears to run correctly in the background. The result image successfully updates the WinForms UI and the Image variable is set.

  • In WinForms you may have issues with async logic, it might be simpler to do the same thing with synchronous logic, specifically because this is WinForms – Chris Schaller Jan 07 '22 at 04:13
  • 1
    Your code is fine, presuming `void LoadImageAsync(string url)` is a top-level event handler. There's no issue with using `async`/`await` in WinForms – CoolBots Jan 07 '22 at 04:21
  • 1
    What is `LoadImageAsync`? How is it used? -- Why do you have `response.GetResponseStream();` twice there? Is that a copy/paste mistake? -- To download simple images from a known source, use the async methods of WebClient. Use a `static` HttpClient if you may have concurrent downloads that are handled by different instances of that Control. -- The `WebResponse` **must** be disposed. – Jimi Jan 07 '22 at 06:15
  • 1
    Yes it was a duplicate. I fixed it. I will make sure to keep disposal in mind. As I understand it I should use `using` for the response always. I execute `LoadImageAsync` from a top-level event handler as @CoolBots described. Thank you for all the advice! – Ohad Farkash Jan 07 '22 at 21:29

3 Answers3

1

As this is a question about optimal methods for utilizing Tasks in C#, I have compiled a final version of my code from recommendations made by other answers.

static readonly HttpClient client = new HttpClient();
public Image Image { 
    get => image;
    set {
        image = value;
        Refresh();
    }
}
private Image image;

public async void LoadImageAsync(string url)
{
    Image = await GetImageAsync(url);
}

private async Task<Image> GetImageAsync(string url)
{
    using (Stream stream = await client.GetStreamAsync(url)) {
        return Image.FromStream(stream);
    }
}

As per others suggestions this utilizes the HttpClient class.

Example execution of the LoadImageAsync method:

void AnyMethodOrEventHandler()
{
    imageControlInstance.LoadImageAsync("http://someurl.com/image.jpg");
}

Thank you all for sharing your knowledge.

0

First, you should not use the void keyword when you have an async task

Second, you don't need to use the setter to refresh the UI, also is better to use a different name for the Image property.

Third, I suggest using HttpClient instead of WebRequest

public Image MyImage { get; set; }

public async Task LoadImageAsync(string url)
{
    MyImage = await GetImageAsync(url);
    Refresh();
}
private async Task<Image> GetImageAsync(string url)
{
    var httpClint = new HttpClient();
    var imageBytes = await httpClint.GetStreamAsync(url);
    return Image.FromStream(imageBytes)
}
AliReza Sabouri
  • 4,355
  • 2
  • 25
  • 37
0

You're using it properly. Your code illustrates exactly the intended use of async/await: you can write asynchronous code in the same way you would write synchronous code. You've written easy-to-read code that doesn't lock up your UI while waiting for a response. That's your goal.

If you haven't already, read over Microsoft's documentation on Asynchronous programming with async and await

Just a note on your use of HttpWebRequest. The documentation says:

Important

We don't recommend that you use HttpWebRequest for new development. Instead, use the System.Net.Http.HttpClient class.

If your code is already written, you can leave it be. I'm pretty sure HttpClient just uses HttpWebRequest in the background anyway. But it's something to think about.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84