1

I am calling an API using these commands:

byte[] messageBytes = System.Text.Encoding.UTF8.GetBytes(message);

var content = new ByteArrayContent(messageBytes);

content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

HttpResponseMessage response = client.PostAsync(ApiUrl, content).Result;

However the code stops executing at the PostAsync line. I put a breakpoint on the next line but it is never reached. It does not throw an error immediately, but a few minutes later it throws an error like:

System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

I presume this means the API is down. What can I do to make PostAsync spit back an error immediately even if the API is down so that I can handle the error and inform the user?

Thank you.

Prashant Pimpale
  • 10,349
  • 9
  • 44
  • 84
Windhoek
  • 1,701
  • 1
  • 15
  • 26
  • Something `DoItAsync` requires that the function is declared as `async Task<...> Something` and the call looks like `response = await DoItAsync(...)` – Alex Kudryashev Jul 18 '18 at 04:00
  • 1
    You could reduce the timeout of the request, but that might cause requests to fail even when the API is available if you set it too low – Janilson Jul 18 '18 at 04:20
  • 1
    Hi @Windhoek, if my answer below helped you please be sure to upvote and mark it as the correct answer. This helps me and also helps others coming here to find out the same answer. Thanks! – pcdev Aug 08 '19 at 06:56
  • @pcdev thanks I upvoted some time ago but also just marked it as an answer. The pre-check approach would work for me. – Windhoek Aug 10 '19 at 10:02

1 Answers1

1

Broadly speaking, what you're asking is "How can I check if an API is available?", and the answer to this depends how low level you want to get, and what you want to do for each level of unavailability:

  1. Is there internet connectivity? Is it worth probing this locally first (as it's relatively quick to check)?
  2. Is the server address correct? If it's wrong it doesn't matter how long you wait. Can the user configure this?
  3. Is the address correct but the server is unable or unwilling to respond? What then?

If you're willing to lump them all into a single "can't contact server in a reasonable amount of time" bucket, there are a few approaches:

Decrease timeouts (beware)

In the case you gave, it sounds like your request is simply timing out: the address or port is wrong, the server is under immense load and can't respond in a timely fashion, you're attempting to contact a non-SSL endpoint using SSL or vice-versa, etc. In any of these cases, you can't know if the request has timed out, until it actually times out. One thing you can do is reduce the HttpClient request timeout. Beware: going too low will cause slow connections to time out on users, which is a worse problem than the one you have.

Pre-check

You could, either before each call, periodically, or at some point early in the client initialisation, do a quick probe of the API to see if it's responsive. This can be spun off into either an async or background task while the UI is being built, etc. This gives you more time to wait for a response, and as an added bonus if the API is responding slowly you can notify your users of this so they know not to expect immediate responses to their clicks. This will improve user experience. If the pre-check fails, you could show an error and advise the user to either check connectivity, check server address (if it's configurable), retry, etc.

Use a CancellationToken

You could pass a CancellationToken into PostAsync with a suitable timeout set, which also allows you to let the user cancel the request if they want to. Read up on CancellationToken for more information.

EDIT: as Alex pointed out, this line is not usually how you deal with async tasks:

HttpResponseMessage response = client.PostAsync(ApiUrl, content).Result;

Change this instead to:

HttpResponseMessage response = await client.PostAsync(ApiUrl, content);

Of course the calling method will then also need to be marked as async, and so on ("It's asyncs, all the way up"), but this is a good thing - it means that your code is not blocking a thread while it waits for a response from the server. Have a read here for some good material.

Hope that helps

pcdev
  • 2,852
  • 2
  • 23
  • 39