简体   繁体   中英

HttpClient - PostAsync doesn’t return

Does anyone know why HttpClient - PostAsync doesn't return. It just does nothing. I have had it working occasionally especially for one off posts but it seems sometimes to not do anything especially under load and it doesn't throw an exception which of course makes my code unreliable and hard to debug.

I have tried adding ConfigureAwait(false) It makes not difference.

I suspect the Task is failing to 'pack'

This is in a core 3.0 console app run on macOS Catalina using visual studio code

This code is pretty much copied from Microsoft's documentation and I'm calling Microsoft Graph when posting.

public static async Task PostAsync(HttpClient httpClient, string url, string token, HttpContent content, Action<JObject> processResult, ILogger log)
    {
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        // content.Headers.Clear();
        content.Headers.Add("Content-Type", "application/json");
        try
        {
            HttpResponseMessage response = await httpClient.PostAsync(url, content);
            if (response.IsSuccessStatusCode)
            {
                var json = await response.Content.ReadAsStringAsync();
                var result = JsonConvert.DeserializeObject(json) as JObject;
                processResult(result);
            }
            else
            {
                var errorContent = await response.Content.ReadAsStringAsync();
                log.LogError(errorContent);
            }
        }
        catch (System.Exception ex)
        {
            log.LogError(ex, ex.Message);
            throw;
        }
    }

Here is an example of the calling code

public async Task SendInvitation(string token, Invitation invitation, ILogger logger)
{
    var stringContent = new StringContent(JsonConvert.SerializeObject(invitation), Encoding.UTF8, "application/json");
    await HttpHelpers.PostAsync(
        Client,
        "https://graph.microsoft.com/v1.0/invitations",
        token,
        stringContent,
        result => logger.LogInformation(DebugHelpers.Print(result)),
        logger);
}

Answered (Sort of)

If I change

HttpResponseMessage response = await httpClient.PostAsync(url, content);

to

HttpResponseMessage response = httpClient.PostAsync(url, content).GetAwaiter().GetResult();

It seems to work but it's slow because what I'm doing is using blocking code. I think this is a quirk of core 3 on macOS. I don't like that this is happening.

More Info

I'm doing a lot of looping.

It seems that if I put all the things I'm awaiting in a taskList it behaves properly.

\\ Pseudo Code
var taskList = new List<Task>();

foreach(var thing in things){
  taskList.Add(HttpHelpers.PostAsync(...things));
}

await Task.WhenAll(taskList);

Please check whether all calls you make in the code execution path support asynchronousity. For example once I spent quite some time figuring out a nuget package called CommandLineParser did not support async calls. I was using it like so :

public static void Main(string[] args) 
{
     Parser.Default.ParseArguments<Options>(args) 
                   .WithParsed(async options => 
                    { await httphelper.PostAsync(...); 
                    } 
}

I fixed the issue by changing it to something like

public static void Main(string[] args) 
{
     Parser.Default.ParseArguments<Options>(args) 
                   .WithParsed(options => 
                    { httphelper.PostAsync(...).Result; 
                    } 
}

So please check you are not using some calls that do not support async in the way.

You can wait for HttpResponseMessage certain condition . Inspect HttpResponseMessage in debug, with 2 given steps. Screenshot of debug process: postAsync debug

  1. return HttpResponseMessage from method with postAsync:

     private static async Task<HttpResponseMessage> methodWithPostAsync(){ ... response = await client.PostAsync(url, data); return response }
  2. call method and wait for response message status :

     Task<HttpResponseMessage> content= methodWithPostAsync(); while (!content.IsCompleted) { Console.WriteLine("busy"); System.Threading.Thread.Sleep(1000); }

像这样尝试ConfigureAwait

HttpResponseMessage response = await httpClient.PostAsync(url, content).ConfigureAwait(false);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM