Resilient Network Connectivity In Xamarin.Forms

Mobile networks are among the least reliable type of network, and your app will likely have to communicate over it, to function. But considering the potential for disruption, we have to ensure our app can accommodate any poor network conditions.

HttpClient

In most cases you will connect to an API via the HttpClient, like this:

public class MyApiClass
{
    public readonly HttpClient _client;

    public MyApiClass()
    {
  	_client = new HttpClient();
	_client.DefaultRequestHeaders.Accept.Clear();
	// Assuming you are connecting to a REST API that accepts JSON
	_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }

    public async Task GetAsync()
    {
	var result = await _client.GetAsync("https://someurl.com/product/1");		
    }

    public async Task SendAsync()
    {
	var product = new Product() { Name = "New Product" };
	var json = JsonConvert.SerializeObject(product);
	var result = await _client.SendAsync(new HttpRequestMessage()
	{
		RequestUri = new Uri("https://someurl.com/product"),
		Content = new StringContent(json)
	});		
    }
}

Pro Tip: Don’t use a using statement with HttpClient, keep a single instance for your whole app. It was designed to work this way.

There are numerous ways this can fail.

GetAsync can throw

  • ArgumentNullException – The request was null.
  • HttpRequestException – The underlying network failed in some way.

SendAsync can throw the above, but also:

  • InvalidOperationException – This message was already sent.

So you would want to wrap the calls to capture those errors and deal with them as necessary. But lets say no error is thrown, we now need to check the status code returned.

public async Task GetAsync()
{
    var result = await _client.GetAsync("https://someurl.com/product/1");	
			
    if (result.IsSuccessStatusCode)
    {
	// Success
    }
    else
    {
	// A non-200 code was returned.
    }
}

If the code returned was a success, you can continue on your way. If it wasn’t, then you need to deal with it. A 400 error is that you sent a bad request to the API, a 500 error means that their API failed.

Connectivity Check

Maybe a page of yours has many network calls to make. You might want to do a check that network connectivity is there first, before trying them. You can do this with the Xam.Plugin.Connectivity plugin. I recommend reading the documentation, and also doing constructor injection, but you can simply check your connectivity like this.

CrossConnectivity.Current.IsConnected

Then, if it is false, you don’t need to attempt all those network calls. However, don’t think that this is a safe guard. If can pass through here, then the network could fail straight after this line of code has run, resulting in the HttpRequestException as mentioned above.

Retry Logic

If you have connectivity issues, you might want to retry, incase it was just an intermittent failure. You can do this with Polly. Here is the same GetAsync method again, however this one will retry up to 3 times, with a 2 second wait in between, if it receives the HttpRequestException. You could also add more exceptions, that it will retry for.

public async Task GetAsync()
{
    var result = await Policy
			.Handle<HttpRequestException>()
			.WaitAndRetry(retryCount: 3,
	                              sleepDurationProvider: (attempt) => TimeSpan.FromSeconds(2))
			.ExecuteAsync(async () => await _client.GetAsync("https://someurl.com/product/1"));

    if (result.IsSuccessStatusCode) { } // Success
    else { }// A non-200 code was returned.
}

Summary

The best way to avoid connectivity issues, is to not make network calls. If your app is suited to it, you could provide limited in-memory caching. I went into this in more detail, in In-Memory Caching in Xamarin. Also, while I showed using the HttpClient, make sure you check out Refit, that helps you create API calls.

Ensuring you check for connectivity, then check for exceptions and possibly retry, then check for status codes, you can easily have your app handle intermittent network issues.


Posted

in

by

Tags: