0

I made a function like this:

public void GetData(string dataToPost)
{
    var url = "some URL";

    using (var client = new WebClient())
    {
        client.Headers[HttpRequestHeader.ContentType] = "application/json";

        client.UploadStringCompleted += (s, e) =>
            {
                Console.WriteLine("Result is here");
                Console.WriteLine(e.Result);
            };

        client.UploadStringAsync(new System.Uri(url), "POST", dataToPost);
    }
}

The problem here is the fact that I want to get a value returned from the server (HTTP response).

I want my function to be asynchronous, so for example I'd like to be able to call it 5 times in a loop, without waiting for each call to return something before next call.

I have no idea how to achieve it. I tried to create some Task object to await it, but Task requires a delegate and I don't know what delegate i could give it.

Te function above uses an event, which is fired when the result comes - so I need to return that result.

How can I do that?

VMAtm
  • 27,943
  • 17
  • 79
  • 125
mnj
  • 2,539
  • 3
  • 29
  • 58
  • It's a console app. I'm quite new to all this, so I'm not sure if I understand what you mean. UploadStringAsync returns void. //edit Looks like someone deleted his comment – mnj Jul 27 '17 at 10:43
  • Sorry, I thought you were using `HttpClient`. You need to subscribe to the `UploadStringCompleted` event which will be called once the call completes. – Igor Jul 27 '17 at 10:45
  • 2
    Would it be possible to switch to `HttpClient` as this has native async/await support, like https://msdn.microsoft.com/en-us/library/hh138242.aspx. – Peter Bons Jul 27 '17 at 10:46
  • @Igor, it doesn't matter for me, if you know a way to do it with HttpClient, I can use it – mnj Jul 27 '17 at 10:46
  • In that case see this previous question/answer: https://stackoverflow.com/a/15176685/1260204 – Igor Jul 27 '17 at 10:48
  • Thanks, HttpClient seems to be a better option. But, just out of curiosity, is it possible to do what i was asking for? Is it an option to make my method asynchronous (it would return Task) – mnj Jul 27 '17 at 11:12

2 Answers2

2

WebClient has an overload that returns a Task<string>:

https://msdn.microsoft.com/en-us/library/hh193920(v=vs.110).aspx

You can fire all your requests and then wait for them with Task.WhenAll:

public void GetData(string dataToPost)
{
    var url = "some URL";
    var url2 = "some other URL";

    using (var client = new WebClient())
    {
        client.Headers[HttpRequestHeader.ContentType] = "application/json";

        var task1 = client.UploadStringTaskAsync(new System.Uri(url), "POST", dataToPost);
        var task2 = client.UploadStringTaskAsync(new System.Uri(url2), "POST", dataToPost);

        var results = Task.WhenAll(task1, task2).Result;

        foreach (var result in results)
        {
            Console.WriteLine("Result is here");
            Console.WriteLine(result);
        }
    }
}

Even better if you can change your GetData to be an async method, you can just await on Task.WhenAll

Stefano d'Antonio
  • 5,874
  • 3
  • 32
  • 45
1

As already been said in comments, HttpClient is more natural choice for such tasks. However, you still may wonder how to provide a task subscribed for an event, and that could be done with TaskCompletionSource<T>, with quite small changes to your code:

private Task<string> GetData(string dataToPost)
{
    var url = "some URL";
    var resultSource = new TaskCompletionSource<string>();

    using (var client = new WebClient())
    {
        client.Headers[HttpRequestHeader.ContentType] = "application/json";

        client.UploadStringCompleted += (s, e) => {
            Console.WriteLine("Result is here");
            Console.WriteLine(e.Result);

            // this will complete the task
            resultSource.SetResult(e.Result);
        };

        client.UploadStringAsync(new System.Uri(url), "POST", dataToPost);
    }

    return resultSource.Task;
}

You can also set a cancellation (with a given token too) and exception (even with multiple exceptions) in this case, so it will naturally fit to your needs. All three methods can be done in Try* fashion for the cases of concurrent event subscription.

Also note the @Stefanod'Antonio' answer for an async method overload.

VMAtm
  • 27,943
  • 17
  • 79
  • 125