📜 ⬆️ ⬇️

Convenient REST for Xamarin Applications

A rich choice of components for working with the network is available for developers at Xamarin, and in today's article we will look at a set of modules that can also be used in PCL projects on Xamarin.Forms.

All articles from the column can be found and read on the link #xamarincolumn , or at the end of the material under the cat.



Refit for convenient client description REST API


The currently most popular protocol for communicating mobile applications with a server is REST in conjunction with Json. Therefore, our today's acquaintance will begin with the library Refit .
')
Refit allows you to describe the specifications for working with the REST service as a simple Interface with a clear set of input and output parameters, including the ability to manipulate HTTP headers for individual requests. For example, take the demo API service httpbin.org :

[Headers("Accept: application/json")] public interface IHttpbinApi { [Get("/basic-auth/{username}/{password}")] Task<AuthResult> BasicAuth(string username, string password, [Header("Authorization")] string authToken, CancellationToken ctx); [Get("/cache")] Task<HttpResponseMessage> CheckIfModified([Header("If-Modified-Since")] string lastUpdateAtString, CancellationToken ctx); [Post("/post")] Task<HttpResponseMessage> FormPost([Body(BodySerializationMethod.UrlEncoded)] FormData data, CancellationToken ctx); } 

After describing this interface, it is fed to the input for Refit:

  var client = new HttpClient(new NativeMessageHandler()) { BaseAddress = new Uri("http://httpbin.org") }; _httpbinApiService = RestService.For<IHttpbinApi>(client); 

The data itself can, if necessary (converting camel case or snake eyes, converting from set to string values), can be extended with attributes from the Json.net library, since it is used in Refit:

  public class AuthResult { [JsonProperty("authenticated")] public bool IsAuthenticated { get; set; } [JsonProperty("user")] public string Login { get; set; } } 

In Refit, the already converted DTO or HttpResponseMessage objects can be obtained as the output value. The latter allows you to get information about the request and response, which can be useful when debugging. If desired, ModernHttpClient can also be used when creating an HttpClient. In general, Refit is a fairly convenient and versatile tool for Xamarin developers as well.

Note 1: to install Refit 3.0 in a PCL project of Xamarin.Forms, you will need to transfer the project to .NET Standard .

Note 2: there is no reference in the Refit documentation to use CancelationToken to cancel active operations, but this mechanism works and is described on the ticket .

Polly


When developing mobile applications, it is often necessary to take into account the factor of signal instability in cellular networks; therefore, when performing network requests, it is often necessary to make repeated attempts. This allows you not to distract once again the user request to repeat the request.

An interesting approach to the use of Refit and Polly was described by Rob Gibbens on his blog (additionally, an example is shown where we prioritize network requests with the help of Fusillade ).

This is how we make a request:

 protected async Task<RequestResult> MakeRequest<T>(Func<CancellationToken, Task<T>> loadingFunction, CancellationToken cancellationToken) { Exception exception = null; var result = default(T); try { result = await Policy.Handle<WebException>().Or<HttpRequestException>() .WaitAndRetryAsync(3, i => TimeSpan.FromMilliseconds(300), (ex, span) => exception = ex) .ExecuteAsync(loadingFunction, cancellationToken); } catch (Exception e) { //      -    DNS exception = e; } //TODO:       return result; } 

Instead of loadingFunction, you must pass your Refit call code:

  var authToken = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}")); return await MakeRequest(ct => _httpbinApiService.BasicAuth(username, password, authToken, ct), cancellationToken); 

So, we integrated Refit, Polly and ModernHttpClient.

Cache


And at the end of the article you can consider using the cache when working with the network. The Xamarin developer has access to all the capabilities of the target platforms, so you can use different DBMS to implement the cache. One of the most popular caches is Akavache , running on top of SQLite .

  var cache = BlobCache.LocalMachine; var cachedObjects = cache.GetAndFetchLatest("objects", GetRemoteObjectAsync, offset => { TimeSpan elapsed = DateTimeOffset.Now - offset; return elapsed > new TimeSpan(hours: 0, minutes: 30, seconds: 0); }); 

You can also use a very convenient mobile Realm DBMS to implement the cache. Below is an example of a Realm based caster:

  public static class LocalCache { private class CachedObject : RealmObject { [PrimaryKey] public string Key { get; set; } public string Value { get; set; } public DateTimeOffset UpdatedAt { get; set; } } private static readonly RealmConfiguration Configuration = new RealmConfiguration("cache.realm", true); private static Realm Db => Realm.GetInstance(Configuration); public static async Task WriteToCache<T>(string key, T data, DateTimeOffset timeStamp) { if (String.IsNullOrEmpty(key) || data == null || timeStamp == DateTimeOffset.MinValue) return; var currentValue = Db.All<CachedObject>().Where(o => o.Key == key).ToList().FirstOrDefault(); if (currentValue == null) await Db.WriteAsync(db => { var newValue = db.CreateObject<CachedObject>(); newValue.Key = key; newValue.UpdatedAt = timeStamp; newValue.Value = JsonConvert.SerializeObject(data); }); else using (var transaction = Db.BeginWrite()) { currentValue.Value = JsonConvert.SerializeObject(data); currentValue.UpdatedAt = timeStamp; transaction.Commit(); } } public static DateTimeOffset CacheLastUpdated(string key) { if (String.IsNullOrEmpty(key)) return DateTimeOffset.MinValue; var currentValue = Db.All<CachedObject>().Where(o => o.Key == key).ToList().FirstOrDefault(); return currentValue?.UpdatedAt ?? DateTimeOffset.MinValue; } public static void RemoveCache(string key) { if (String.IsNullOrEmpty(key)) return; var currentValue = Db.All<CachedObject>().Where(o => o.Key == key).ToList().FirstOrDefault(); if (currentValue == null) return; using (var transaction = Db.BeginWrite()) { Db.Remove(currentValue); transaction.Commit(); } } public static T GetFromCache<T>(string key) { if (String.IsNullOrEmpty(key)) return default(T); var currentValue = Db.All<CachedObject>().Where(o => o.Key == key).ToList().FirstOrDefault(); return currentValue?.Value == null ? default(T) : JsonConvert.DeserializeObject<T>(currentValue.Value); } public static void ClearCache() { Realm.DeleteRealm(Configuration); } } 

Conclusion


So, today we looked at using Refit , Json.net , ModernHttpClient , Polly and Realm when integrating with the REST API. In the next article, we will look at integrating Xamarin with external services and Azure.

About the authors



Vyacheslav Chernikov - head of development at Binwell . In the past, he was one of the Nokia Champion and Qt Certified Specialists, currently he is the Xamarin and Azure platform specialist. He came to the sphere of mobile in 2005, since 2008 he has been developing mobile applications: he started with Symbian, Maemo, Meego, Windows Mobile, then switched to iOS, Android and Windows Phone.

Other articles by the author:


useful links


Source: https://habr.com/ru/post/310704/


All Articles