1

I'm trying to upload data to an external webservice, i'm using the WebClients UploadDataTaskAsync to do this asynchronously. but it never returns. I've tested this using the synchronous call and it will timeout eventually.

public Notification Notify(Notification notification)
{
    var messageXml = MessageFactory.Create(notification);
    var statusCode = SendWebRequestAsync(messageXml);

    notification.ProcessedAttempts++;
    if (statusCode.Result == HttpStatusCode.OK)
    {
        notification.Processed = true;
        notification.DateProcessed = DateTime.UtcNow;
    }
    return notification;
}

private async Task<HttpStatusCode> SendWebRequestAsync(string message)
{
    using (var webClient = new WebClient())
    {
        byte[] data = message.ToUtf8Bytes();

        var uri = new Uri(url);
        try
        {
            webClient.UploadDataCompleted += WebClient_UploadDataCompleted;
            var result = await webClient.UploadDataTaskAsync(uri, "POST", data);
            string response = Encoding.UTF8.GetString(result);

            if (response == "")
                return HttpStatusCode.OK;
            return HttpStatusCode.NoContent;
        }
        catch (WebException ex)
        {
            if (ex.Status == WebExceptionStatus.ProtocolError)
            {
                var response = ex.Response as HttpWebResponse;
                if (response != null)
                {
                    return response.StatusCode;
                }
            }
            // no http status code available
            return HttpStatusCode.ServiceUnavailable; // guess
        }
        catch (Exception)
        {
            return HttpStatusCode.InternalServerError;
        }
    }
}

private void WebClient_UploadDataCompleted(object sender, UploadDataCompletedEventArgs e)
{
    Console.WriteLine(e.Result);
} 
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
InitLipton
  • 2,395
  • 5
  • 30
  • 47
  • What sort of application is this? I strongly suspect that the problem is your use of `statusCode.Result`, but it's hard to tell without knowing more. – Jon Skeet Feb 22 '16 at 15:59
  • @JonSkeet its a MVC web application hosted in Azure. – InitLipton Feb 22 '16 at 16:00
  • 3
    Are you sure that this is not `SynchronizationContext` issue as in this SO question: https://stackoverflow.com/questions/10343632/httpclient-getasync-never-returns-when-using-await-async ? It look very similar – Alex F Feb 22 '16 at 16:01
  • So you tested it sync and async and it doesn't work either way? Are you sure your URL is correct? – nvoigt Feb 22 '16 at 16:01
  • 1
    Yup, it's the same issue, basically, due to the use of the `Result` property. – Jon Skeet Feb 22 '16 at 16:04

1 Answers1

2

You're calling statusCode.Result which is the classic ASP.NET deadlock. This makes no sense because you're apparently using async IO to get scalability benefits and then destroying that by blocking.

Don't block.

Also, it looks like HttpClient could reduce the code that you have there a bit.

usr
  • 168,620
  • 35
  • 240
  • 369