Hunter Mitchell
Hunter Mitchell

Reputation: 7293

Writing to Console on async event

I am using WebClient to submit an array of HTTP requests to a server (order doesn't matter).

Instead of sending a request, waiting, sending, waiting, etc. I wanted to send as many as possible and just wait for the responses as they come, however, and issue arises when I need to write to the console after a specific request was completed.

The output looks fine, then I start to get multiple request messages, then a group of Responses/Errors, rather than the Request Message followed by the response.

Is there any way to block any other Console Writes until each block finishes?

int currentRequest = 1;
for (int i = 0; i < requests.Count; i++) {
    using (var webclient = new WebClient())
    {
        webclient.DownloadStringCompleted += (sender, e) =>
        {
            Console.WriteLine();
            Info("Request: " + currentRequest + "/" + requests.Count);
            if (e.Error == null) {
                // Do something with e.Result
            } else {
                Console.WriteLine("Error: " + e.Error.Message);
            }
            currentRequest += 1;
        };
        webclient.DownloadStringAsync(new Uri("URL HERE"));
    }
}

On another note: I don't feel like this is how I should be handling requests (asynchronously), correct me if i'm wrong.

Upvotes: 0

Views: 163

Answers (1)

Remus Rusanu
Remus Rusanu

Reputation: 294277

Is there any way to block any other Console Writes until each block finishes?

Yes, this is what lock is for.

int currentRequest = 1;
Object lockObject = new Object();
for (int i = 0; i < requests.Count; i++) {
    using (var webclient = new WebClient())
    {
        webclient.DownloadStringCompleted += (sender, e) =>
        {
            lock(lockObject) 
            {
               Console.WriteLine();
               ...                
               currentRequest += 1;
            }
        };
        webclient.DownloadStringAsync(new Uri("URL HERE"));
    }
}

Strictly this does not block other 'console writes', but it does serialize the processing of each response.

I don't feel like this is how I should be handling requests (asynchronously)

That is true. You should be using await, Task and Parallel.ForEach. I'm not going to write a full example because for handling URLS, there are way way way more complications than just the async. I recommend you also read about ServicePointManager.DefaultConnectionLimit and understand why perhaps your downloads async are perhaps slower than you expect.

Upvotes: 1

Related Questions