- PVSM.RU - https://www.pvsm.ru -
Разработчикам на Xamarin доступен богатый выбор компонентов для работы с сетью, и в сегодняшней нашей статье мы рассмотрим набор модулей, которые также могут быть использованы в PCL-проектах на Xamarin.Forms.
Все статьи из колонки можно найти и прочитать по ссылке #xamarincolumn [1], или в конце материала под катом.
Самым популярным в настоящее время протоколом для общения мобильных приложений с сервером является REST в связке с Json. Поэтому наше сегодняшнее знакомство начнем с библиотеки Refit [2].
Refit позволяет описать спецификации для работы с REST-сервисом в виде простого Interface с понятным набором входных и выходных параметров, включая возможность манипулировать HTTP-заголовками для отдельных запросов. Для примера возьмем демо-API сервиса httpbin.org [3]:
[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);
}
После описания данного интерфейса, он подается на вход для Refit:
var client = new HttpClient(new NativeMessageHandler())
{
BaseAddress = new Uri("http://httpbin.org")
};
_httpbinApiService = RestService.For<IHttpbinApi>(client);
Сами данные можно при необходимости (конвертации camel case или snake eyes, преобразование из множества в строковые значения) можно расширить аттрибутами из библиотеки Json.net [4], так как именно она используется в Refit:
public class AuthResult
{
[JsonProperty("authenticated")]
public bool IsAuthenticated { get; set; }
[JsonProperty("user")]
public string Login { get; set; }
}
В Refit в качестве выходного значения можно получить уже преобразованные объекты DTO [5] или HttpResponseMessage. Последний позволяет получить информацию о запросе и ответе, что может быть полезно при отладке. При желании также может использоваться ModernHttpClient при создании HttpClient. В целом, Refit — достаточно удобный и универсальный инструмент для Xamarin-разработчиков в том числе.
Примечание 1: для установки Refit 3.0 в PCL-проект Xamarin.Forms потребуется перевести проект на .NET Standard [6].
Примечание 2: в документации Refit нет упоминания на использование CancelationToken для отмены активных операций, но данный механизм работает и описан в тикете [7].
При разработке мобильных приложений часто приходится учитывать фактор нестабильности сигнала в сотовых сетях, поэтому при выполнении сетевых запросов часто возникает необходимости делать повторные попытки. Это позволяет не отвлекать лишний раз пользователя просьбой повторить запрос.
Интересный подход по использованию Refit и Polly [8] описал Rob Gibbens в своем блоге [9] (дополнительно там показан пример приоретизацией сетевых запросов с помощью Fusillade [10]).
Вот так мы совершаем запрос:
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;
}
Вместо loadingFunction необходимо передать ваш код обращения к Refit:
var authToken = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"));
return await MakeRequest(ct => _httpbinApiService.BasicAuth(username, password, authToken, ct), cancellationToken);
Итак, мы интегрировали Refit, Polly и ModernHttpClient.
И в завершении статьи можно рассмотреть использование кэша при работе с сетью. Xamarin-разработчику доступны все возможности целевых платформ, поэтому для реализации кэша можно использовать различные СУБД. Одним из самых популярных кэшеров выступает Akavache [11], работающий поверх SQLite [12].
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);
});
Также можно использовать для реализации кэша очень удобную мобильную СУБД Realm [13]. Ниже представлен пример кэшера на базе Realm:
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);
}
}
Итак, сегодня мы рассмотрели использование Refit [2], Json.net [4], ModernHttpClient [14], Polly [8] и Realm [13] при интеграции с REST API. В следующей статье мы рассмотрим вопросы интеграции Xamarin с внешними сервисами и Azure.
Вячеслав Черников — руководитель отдела разработки компании Binwell [15]. В прошлом — один из Nokia Champion и Qt Certified Specialist, в настоящее время — специалист по платформам Xamarin и Azure. В сферу mobile пришел в 2005 году, с 2008 года занимается разработкой мобильных приложений: начинал с Symbian, Maemo, Meego, Windows Mobile, потом перешел на iOS, Android и Windows Phone.
1. Быстрое создание MVP (minimum viable product) на базе Microsoft Azure и Xamarin.Forms [16].
2. Готовим Xamarin.Forms: настройка окружения и первые шаги [17].
3. Повышаем эффективность работы в Xamarin.Forms [18].
4. Работаем с состояниями экранов в Xamarin.Forms [19].
Автор: Microsoft
Источник [23]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-2/191001
Ссылки в тексте:
[1] #xamarincolumn: https://habrahabr.ru/search/?target_type=posts&q=%5Bxamarincolumn%5D&order_by=date
[2] Refit: https://github.com/paulcbetts/refit
[3] httpbin.org: http://httpbin.org
[4] Json.net: https://github.com/JamesNK/Newtonsoft.Json
[5] DTO: https://ru.wikipedia.org/wiki/DTO
[6] перевести проект на .NET Standard: https://github.com/paulcbetts/refit/issues/260
[7] тикете: https://github.com/paulcbetts/refit/issues/88
[8] Polly: https://github.com/App-vNext/Polly
[9] блоге: http://arteksoftware.com/resilient-network-services-with-xamarin/
[10] Fusillade: https://github.com/paulcbetts/Fusillade
[11] Akavache: https://github.com/akavache/Akavache
[12] SQLite: https://www.sqlite.org/
[13] Realm: https://realm.io/docs/xamarin/latest/
[14] ModernHttpClient: https://github.com/paulcbetts/ModernHttpClient
[15] Binwell: http://www.binwell.com/
[16] Быстрое создание MVP (minimum viable product) на базе Microsoft Azure и Xamarin.Forms: https://habrahabr.ru/company/microsoft/blog/281897/
[17] Готовим Xamarin.Forms: настройка окружения и первые шаги: https://habrahabr.ru/company/microsoft/blog/303630/
[18] Повышаем эффективность работы в Xamarin.Forms: https://habrahabr.ru/company/microsoft/blog/304678/
[19] Работаем с состояниями экранов в Xamarin.Forms: https://habrahabr.ru/company/microsoft/blog/307890/
[20] по ссылке: https://habrahabr.ru/company/microsoft/blog/281142/
[21] бесплатные предложения для разработчиков: https://www.visualstudio.com/ru-ru/products/free-developer-offers-vs.aspx
[22] Visual Studio Dev Essentials: https://www.visualstudio.com/ru-ru/products/visual-studio-dev-essentials-vs.aspx
[23] Источник: https://habrahabr.ru/post/310704/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.