Leandro Bardelli
Leandro Bardelli

Reputation: 11588

C# httpclient with Task<string> that return content

I've the following function but can't debug it because response never come. Service on the other side is working. Any help will be preciated, I can't deduce how must be do it with other answers in SO

    public async Task<string> PostObjectToWebServiceAsJSON(object objectToPost, string validatorName, string method)
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri("myuri" + "/" + method);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            // HTTP POST
            var response = await client.PostAsJsonAsync("", objectToPost);
            if (response.IsSuccessStatusCode)
            {
                return await response.Content.ReadAsStringAsync();
            }
            else
            {
                string errplugin = "Error";

                return null;
            }
        }
    }

This is how I call it:

    public PaymentResponseInternal Post(some stuff here)
    {
        Task<string> retornoPluginAsync = PostObjectToWebServiceAsJSON(some stuff here);

        retornoPluginAsync.Wait();
        string result = retornoPluginAsync.Result;

        return JsonConvert.DeserializeObject<PaymentResponseInternal>(result);
    }

Upvotes: 0

Views: 2970

Answers (2)

mm8
mm8

Reputation: 169330

As mentioned in the comments, you should make PaymentResponseInternal an async method that returns a Task<PaymentResponseInternal> and await it.

You shouldn’t mix synchronous and asynchronous code. One of the reasons for this is that you might deadlock as you have discovered here. Please refer to @Stephen Cleary's article on the subject for more information: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

If you can't make your Post method async for some reason, you could try not to capture the context in the PostObjectToWebServiceAsJSON method by calling ConfigureAwait(false) after each await:

public async Task<string> PostObjectToWebServiceAsJSON(object objectToPost, string validatorName, string method)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri("myuri" + "/" + method);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        var response = await client.PostAsJsonAsync("", objectToPost).ConfigureAwait(false);
        if (response.IsSuccessStatusCode)
        {
            return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
        }
        else
        {
            return null;
        }
    }
}

Please refer to @Stephen Cleary's blog post for information about this: https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Upvotes: 3

GeorgDangl
GeorgDangl

Reputation: 2192

With your update to the question, you're running into a deadlock situation when you call PostObjectToWebServiceAsJSON synchronously. You should add a call to retornoPluginAsync.ConfigureAwait(false); before you Wait() for it. ConfigureAwait(false) configures the Task to not require the original call context and should, in your case, solve the deadlock.

    public PaymentResponseInternal Post(some stuff here)
    {
        Task<string> retornoPluginAsync = PostObjectToWebServiceAsJSON(some stuff here);
        retornoPluginAsync.ConfigureAwait(false); // Add this
        retornoPluginAsync.Wait();
        string result = retornoPluginAsync.Result;

        return JsonConvert.DeserializeObject<PaymentResponseInternal>(result);
    }

Upvotes: 1

Related Questions