Доступ к удаленным данным
Примечание.
Эта электронная книга была опубликована весной 2017 года и с тех пор не была обновлена. Есть много в книге, которая остается ценным, но некоторые из материалов устарели.
Многие современные веб-решения используют веб-службы, размещенные на веб-серверах, для обеспечения функциональности удаленных клиентских приложений. Предоставляемые веб-службой операции составляют веб-API.
Клиентские приложения должны использовать веб-API, не зная, как реализуются данные или операции, предоставляемые API. Это требует, чтобы API соблюдался общими стандартами, которые позволяют клиентскому приложению и веб-службе согласиться с форматами данных, используемыми, и структурой данных, которые обмениваются между клиентскими приложениями и веб-службой.
Общие сведения о передаче состояния представления
Передача репрезентативного состояния (REST) — это архитектурный стиль для создания распределенных систем на основе гипермедии. Основное преимущество модели REST заключается в том, что она основана на открытых стандартах и не привязывает реализацию модели или клиентских приложений, которые обращаются к ней к какой-либо конкретной реализации. Поэтому веб-служба REST может быть реализована с помощью Microsoft ASP.NET Core MVC, а клиентские приложения могут разрабатываться с помощью любого языка и набора инструментов, которые могут создавать HTTP-запросы и анализировать HTTP-ответы.
Модель REST использует схему навигации для представления объектов и служб по сети, называемых ресурсами. Системы, реализующие REST, обычно используют протокол HTTP для передачи запросов для доступа к этим ресурсам. В таких системах клиентское приложение отправляет запрос в виде URI, определяющего ресурс, и метод HTTP (например, GET, POST, PUT или DELETE), указывающий на операцию, выполняемую в этом ресурсе. Текст HTTP-запроса содержит все данные, необходимые для выполнения операции.
Примечание.
REST определяет модель запроса без отслеживания состояния. Поэтому HTTP-запросы должны быть независимыми и могут выполняться в любом порядке.
Ответ от запроса REST использует стандартные коды состояния HTTP. Например, запрос, возвращающий допустимые данные, должен включать код HTTP-ответа 200 (ОК), в то время как запрос, по которому не удалось найти или удалить указанный ресурс, должен вернуть ответ, включающий код состояния HTTP 404 (не найдено).
Веб-API RESTful предоставляет набор подключенных ресурсов и предоставляет основные операции, позволяющие приложению управлять этими ресурсами и легко перемещаться между ними. По этой причине URI, составляющие типичный веб-API RESTful, ориентированы на данные, предоставляемые им, и используют средства, предоставляемые HTTP для работы с данными.
Данные, включенные клиентским приложением в HTTP-запросе, и соответствующие сообщения ответа от веб-сервера, могут быть представлены в различных форматах, известных как типы носителей. Когда клиентское приложение отправляет запрос, возвращающий данные в тексте сообщения, он может указать типы носителей, которые он может обрабатывать в Accept
заголовке запроса. Если веб-сервер поддерживает этот тип носителя, он может ответить с ответом, который содержит Content-Type
заголовок, указывающий формат данных в тексте сообщения. Затем это ответственность клиентского приложения, чтобы проанализировать ответное сообщение и интерпретировать результаты в тексте сообщения соответствующим образом.
Дополнительные сведения о REST см. в статье о разработке API и реализации API.
Использование API RESTful
Мобильное приложение eShopOnContainers использует шаблон Model-View-ViewModel (MVVM), а элементы модели шаблона представляют сущности домена, используемые в приложении. Классы контроллера и репозитория в эталонном приложении eShopOnContainers принимают и возвращают многие из этих объектов модели. Поэтому они используются в качестве объектов передачи данных (DTO), которые содержат все данные, передаваемые между мобильным приложением и контейнерными микрослужбами. Основное преимущество использования DTOs для передачи данных и получения данных из веб-службы заключается в том, что путем передачи дополнительных данных в одном удаленном вызове приложение может уменьшить количество удаленных вызовов, которые необходимо сделать.
Выполнение веб-запросов
Мобильное приложение eShopOnContainers использует HttpClient
класс для выполнения запросов по протоколу HTTP, а JSON используется в качестве типа носителя. Этот класс предоставляет функциональные возможности для асинхронной отправки HTTP-запросов и получения HTTP-ответов из определяемого ресурса URI. Класс HttpResponseMessage
представляет сообщение HTTP-ответа, полученное от REST API после выполнения HTTP-запроса. Он содержит сведения об ответе, включая код состояния, заголовков и любой текст. HttpContent
Класс представляет тело HTTP и заголовки содержимого, таких как Content-Type
и Content-Encoding
. Содержимое можно считывать с помощью любого из ReadAs
методов, таких как ReadAsStringAsync
и ReadAsByteArrayAsync
в зависимости от формата данных.
Создание запроса GET
Класс CatalogService
используется для управления процессом извлечения данных из микрослужбы каталога. В методе RegisterDependencies
ViewModelLocator
в классе CatalogService
класс регистрируется в качестве сопоставления типов с ICatalogService
типом с контейнером внедрения зависимостей Autofac. Затем, когда создается экземпляр CatalogViewModel
класса, его конструктор принимает ICatalogService
тип, который разрешает Autofac, возвращая экземпляр CatalogService
класса. Дополнительные сведения о внедрении зависимостей см. в разделе "Введение в внедрение зависимостей".
На рисунке 10-1 показано взаимодействие классов, которые считывают данные каталога из микрослужбы каталога для отображения данными CatalogView
каталога.
Рис. 10-1. Получение данных из микрослужбы каталога
CatalogView
При переходе OnInitialize
метод в CatalogViewModel
классе вызывается. Этот метод извлекает данные каталога из микрослужбы каталога, как показано в следующем примере кода:
public override async Task InitializeAsync(object navigationData)
{
...
Products = await _productsService.GetCatalogAsync();
...
}
Этот метод вызывает GetCatalogAsync
метод экземпляра CatalogService
, внедренного в CatalogViewModel
автофак. Метод GetCatalogAsync
показан в следующем примере кода:
public async Task<ObservableCollection<CatalogItem>> GetCatalogAsync()
{
UriBuilder builder = new UriBuilder(GlobalSetting.Instance.CatalogEndpoint);
builder.Path = "api/v1/catalog/items";
string uri = builder.ToString();
CatalogRoot catalog = await _requestProvider.GetAsync<CatalogRoot>(uri);
...
return catalog?.Data.ToObservableCollection();
}
Этот метод создает URI, определяющий ресурс, в который будет отправлен запрос, и использует RequestProvider
класс для вызова метода GET HTTP в ресурсе, прежде чем возвращать результаты в CatalogViewModel
ресурс. Класс RequestProvider
содержит функциональные возможности, которые отправляет запрос в виде URI, который определяет ресурс, метод HTTP, указывающий операцию, выполняемую на этом ресурсе, и текст, содержащий все данные, необходимые для выполнения операции. Сведения о том, как RequestProvider
класс внедряется в приложение, см. в CatalogService class
разделе "Введение в внедрение зависимостей".
В следующем примере кода показан GetAsync
метод в RequestProvider
классе:
public async Task<TResult> GetAsync<TResult>(string uri, string token = "")
{
HttpClient httpClient = CreateHttpClient(token);
HttpResponseMessage response = await httpClient.GetAsync(uri);
await HandleResponse(response);
string serialized = await response.Content.ReadAsStringAsync();
TResult result = await Task.Run(() =>
JsonConvert.DeserializeObject<TResult>(serialized, _serializerSettings));
return result;
}
Этот метод вызывает CreateHttpClient
метод, который возвращает экземпляр HttpClient
класса с соответствующим набором заголовков. Затем он отправляет асинхронный запрос GET в ресурс, определенный URI, с ответом, хранящимся в экземпляре HttpResponseMessage
. Затем HandleResponse
вызывается метод, который вызывает исключение, если ответ не содержит код состояния HTTP успешного выполнения. Затем ответ считывается как строка, преобразуется из JSON в CatalogRoot
объект и возвращается в объект CatalogService
.
Метод CreateHttpClient
показан в следующем примере кода:
private HttpClient CreateHttpClient(string token = "")
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
if (!string.IsNullOrEmpty(token))
{
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
}
return httpClient;
}
Этот метод создает новый экземпляр HttpClient
класса и задает Accept
заголовок всех запросов, сделанных HttpClient
экземпляром application/json
, что указывает на то, что содержимое любого ответа будет отформатировано с помощью JSON. Затем, если маркер доступа был передан в качестве аргумента CreateHttpClient
методу, он добавляется в Authorization
заголовок всех запросов, сделанных HttpClient
экземпляром, префиксом строки Bearer
. Дополнительные сведения об авторизации см. в разделе "Авторизация".
GetAsync
При вызове HttpClient.GetAsync
Items
метода в классе вызывается метод в RequestProvider
CatalogController
классе в проекте Catalog.API, который показан в следующем примере кода:
[HttpGet]
[Route("[action]")]
public async Task<IActionResult> Items(
[FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0)
{
var totalItems = await _catalogContext.CatalogItems
.LongCountAsync();
var itemsOnPage = await _catalogContext.CatalogItems
.OrderBy(c=>c.Name)
.Skip(pageSize * pageIndex)
.Take(pageSize)
.ToListAsync();
itemsOnPage = ComposePicUri(itemsOnPage);
var model = new PaginatedItemsViewModel<CatalogItem>(
pageIndex, pageSize, totalItems, itemsOnPage);
return Ok(model);
}
Этот метод извлекает данные каталога из базы данных SQL с помощью EntityFramework и возвращает его как ответное сообщение, включающее код состояния HTTP, а также коллекцию отформатированных CatalogItem
экземпляров JSON.
Выполнение запроса POST
Класс BasketService
используется для управления процессом извлечения и обновления данных с помощью микрослужбы корзины. В методе RegisterDependencies
ViewModelLocator
в классе BasketService
класс регистрируется в качестве сопоставления типов с IBasketService
типом с контейнером внедрения зависимостей Autofac. Затем, когда создается экземпляр BasketViewModel
класса, его конструктор принимает IBasketService
тип, который разрешает Autofac, возвращая экземпляр BasketService
класса. Дополнительные сведения о внедрении зависимостей см. в разделе "Введение в внедрение зависимостей".
На рис. 10-2 показано взаимодействие классов, отправляющих данные корзины, отображаемые BasketView
микрослужбой корзины.
Рис. 10-2. Отправка данных в микрослужбу корзины
При добавлении элемента в корзину ReCalculateTotalAsync
покупок вызывается метод в BasketViewModel
классе. Этот метод обновляет общее значение элементов в корзине и отправляет данные корзины в микрослужбу корзины, как показано в следующем примере кода:
private async Task ReCalculateTotalAsync()
{
...
await _basketService.UpdateBasketAsync(new CustomerBasket
{
BuyerId = userInfo.UserId,
Items = BasketItems.ToList()
}, authToken);
}
Этот метод вызывает UpdateBasketAsync
метод экземпляра BasketService
, внедренного в BasketViewModel
автофак. В следующем методе UpdateBasketAsync
показан метод:
public async Task<CustomerBasket> UpdateBasketAsync(CustomerBasket customerBasket, string token)
{
UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BasketEndpoint);
string uri = builder.ToString();
var result = await _requestProvider.PostAsync(uri, customerBasket, token);
return result;
}
Этот метод создает URI, определяющий ресурс, в который будет отправлен запрос, и использует RequestProvider
класс для вызова метода POST HTTP в ресурсе, прежде чем возвращать результаты в BasketViewModel
ресурс. Обратите внимание, что маркер доступа, полученный из IdentityServer во время проверки подлинности, необходим для авторизации запросов в микрослужбу корзины. Дополнительные сведения об авторизации см. в разделе "Авторизация".
В следующем примере кода показан один из PostAsync
методов в RequestProvider
классе:
public async Task<TResult> PostAsync<TResult>(
string uri, TResult data, string token = "", string header = "")
{
HttpClient httpClient = CreateHttpClient(token);
...
var content = new StringContent(JsonConvert.SerializeObject(data));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = await httpClient.PostAsync(uri, content);
await HandleResponse(response);
string serialized = await response.Content.ReadAsStringAsync();
TResult result = await Task.Run(() =>
JsonConvert.DeserializeObject<TResult>(serialized, _serializerSettings));
return result;
}
Этот метод вызывает CreateHttpClient
метод, который возвращает экземпляр HttpClient
класса с соответствующим набором заголовков. Затем он отправляет асинхронный запрос POST в ресурс, определенный URI, с сериализованными данными корзины, отправляемыми в формате JSON, и ответ, хранящийся в экземпляре HttpResponseMessage
. Затем HandleResponse
вызывается метод, который вызывает исключение, если ответ не содержит код состояния HTTP успешного выполнения. Затем ответ считывается как строка, преобразуется из JSON в CustomerBasket
объект и возвращается в объект BasketService
. Дополнительные сведения о методе CreateHttpClient
см. в разделе "Создание запроса GET".
PostAsync
При вызове HttpClient.PostAsync
Post
метода в классе вызывается метод в RequestProvider
BasketController
классе в проекте Basket.API, который показан в следующем примере кода:
[HttpPost]
public async Task<IActionResult> Post([FromBody]CustomerBasket value)
{
var basket = await _repository.UpdateBasketAsync(value);
return Ok(basket);
}
Этот метод использует экземпляр RedisBasketRepository
класса для сохранения данных корзины в кэше Redis и возвращает его как ответное сообщение, включающее код состояния HTTP и отформатированный CustomerBasket
экземпляр JSON.
Выполнение запроса DELETE
На рисунке 10-3 показаны взаимодействия классов, которые удаляют данные корзины из микрослужбы корзины.CheckoutView
Рис. 10-3. Удаление данных из микрослужбы корзины
При вызове CheckoutAsync
процесса выхода вызывается метод в CheckoutViewModel
классе. Этот метод создает новый заказ перед очисткой корзины покупок, как показано в следующем примере кода:
private async Task CheckoutAsync()
{
...
await _basketService.ClearBasketAsync(_shippingAddress.Id.ToString(), authToken);
...
}
Этот метод вызывает ClearBasketAsync
метод экземпляра BasketService
, внедренного в CheckoutViewModel
автофак. В следующем методе ClearBasketAsync
показан метод:
public async Task ClearBasketAsync(string guidUser, string token)
{
UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BasketEndpoint);
builder.Path = guidUser;
string uri = builder.ToString();
await _requestProvider.DeleteAsync(uri, token);
}
Этот метод создает URI, определяющий ресурс, в который будет отправлен запрос, и использует RequestProvider
класс для вызова метода DELETE HTTP в ресурсе. Обратите внимание, что маркер доступа, полученный из IdentityServer во время проверки подлинности, необходим для авторизации запросов в микрослужбу корзины. Дополнительные сведения об авторизации см. в разделе "Авторизация".
В следующем примере кода показан DeleteAsync
метод в RequestProvider
классе:
public async Task DeleteAsync(string uri, string token = "")
{
HttpClient httpClient = CreateHttpClient(token);
await httpClient.DeleteAsync(uri);
}
Этот метод вызывает CreateHttpClient
метод, который возвращает экземпляр HttpClient
класса с соответствующим набором заголовков. Затем он отправляет асинхронный запрос DELETE в ресурс, определенный URI. Дополнительные сведения о методе CreateHttpClient
см. в разделе "Создание запроса GET".
DeleteAsync
При вызове HttpClient.DeleteAsync
Delete
метода в классе вызывается метод в RequestProvider
BasketController
классе в проекте Basket.API, который показан в следующем примере кода:
[HttpDelete("{id}")]
public void Delete(string id)
{
_repository.DeleteBasketAsync(id);
}
Этот метод использует экземпляр RedisBasketRepository
класса для удаления данных корзины из кэша Redis.
Кэширование данных
Производительность приложения можно улучшить, кэширование часто доступных данных для быстрого хранения, расположенного рядом с приложением. Если быстрое хранилище расположено ближе к приложению, чем исходный источник, кэширование может значительно повысить время отклика при получении данных.
Наиболее распространенная форма кэширования — кэширование через чтение, где приложение извлекает данные, ссылаясь на кэш. Если данные находятся не в кэше, они извлекаются из хранилища данных и добавляются в кэш. Приложения могут реализовать кэширование с помощью шаблона кэширования в сторону кэша. Этот шаблон определяет, находится ли элемент в кэше. Если элемент не находится в кэше, он считывается из хранилища данных и добавляется в кэш. Дополнительные сведения см. в шаблоне cache-Aside .
Совет
Кэшируйте данные, которые часто читаются и которые часто изменяются. Эти данные можно добавить в кэш по запросу при первом получении приложением. Это означает, что приложению необходимо получить данные только один раз из хранилища данных, а последующий доступ может быть удовлетворен с помощью кэша.
Распределенные приложения, такие как эталонное приложение eShopOnContainers, должны предоставлять один или оба из следующих кэшей:
- Общий кэш, к которому можно получить доступ с помощью нескольких процессов или компьютеров.
- Частный кэш, где данные хранятся локально на устройстве под управлением приложения.
Мобильное приложение eShopOnContainers использует частный кэш, где данные хранятся локально на устройстве, на котором выполняется экземпляр приложения. Сведения о кэше, используемом справочным приложением eShopOnContainers, см. в статье .NET Microservices: Архитектура контейнерных приложений .NET.
Совет
Думайте о кэше как временном хранилище данных, которое может исчезнуть в любое время. Убедитесь, что данные хранятся в исходном хранилище данных, а также в кэше. Вероятность потери данных будет сведена к минимуму, если кэш становится недоступным.
Управление истечением срока действия данных
Нецелесообразно ожидать, что кэшированные данные всегда будут согласованы с исходными данными. Данные в исходном хранилище данных могут измениться после его кэширования, что приведет к тому, что кэшированные данные становятся устаревшими. Поэтому приложения должны реализовать стратегию, которая помогает обеспечить актуальность данных в кэше, но также может обнаруживать и обрабатывать ситуации, возникающие при возникновении устаревших данных в кэше. Большинство механизмов кэширования позволяют настроить кэш для истечения срока действия данных и, следовательно, сократить период, для которого данные могут быть устаревшими.
Совет
Задайте время истечения срока действия по умолчанию при настройке кэша. Многие кэши реализуют срок действия, который делает данные недействительными и удаляет их из кэша, если он недоступен в течение указанного периода. Однако при выборе срока действия необходимо учесть осторожность. Если это сделано слишком коротко, срок действия данных будет истекает слишком быстро, и преимущества кэширования будут сокращены. Если это слишком долго, данные рискуют стать устаревшими. Поэтому срок действия должен соответствовать шаблону доступа для приложений, использующих данные.
Когда срок действия кэшированных данных истекает, его следует удалить из кэша, а приложение должно получить данные из исходного хранилища данных и поместить его обратно в кэш.
Также возможно, что кэш может заполниться, если данные могут оставаться слишком долго. Таким образом, запросы на добавление новых элементов в кэш могут потребоваться для удаления некоторых элементов в процессе, известном как вытеснение. Службы кэширования обычно вытесняют данные по крайней мере недавно использованных. Однако существуют и другие политики вытеснения, в том числе недавно используемые и первый выход. Дополнительные сведения см . в руководстве по кэшированию.
Кэширование изображений
Мобильное приложение eShopOnContainers использует удаленные образы продуктов, которые получают преимущества от кэширования. Эти изображения отображаются элементом Image
управления и CachedImage
элементом управления, предоставляемым библиотекой FFImageLoading .
Элемент Xamarin.FormsImage
управления поддерживает кэширование скачанных изображений. Кэширование включено по умолчанию и будет хранить образ локально в течение 24 часов. Кроме того, срок действия можно настроить с помощью CacheValidity
свойства. Дополнительные сведения см. в разделе "Скачанный кэширование изображений".
Элемент управления FFImageLoading CachedImage
является заменой Xamarin.FormsImage
элемента управления, предоставляя дополнительные свойства, обеспечивающие дополнительные функциональные возможности. Среди этих функций элемент управления обеспечивает настраиваемое кэширование, поддерживая ошибки и загрузку заполнителей изображений. В следующем примере кода показано, как мобильное приложение eShopOnContainers использует CachedImage
элемент управления в ProductTemplate
шаблоне данных, используемом ListView
элементом управления:CatalogView
<ffimageloading:CachedImage
Grid.Row="0"
Source="{Binding PictureUri}"
Aspect="AspectFill">
<ffimageloading:CachedImage.LoadingPlaceholder>
<OnPlatform x:TypeArguments="ImageSource">
<On Platform="iOS, Android" Value="default_campaign" />
<On Platform="UWP" Value="Assets/default_campaign.png" />
</OnPlatform>
</ffimageloading:CachedImage.LoadingPlaceholder>
<ffimageloading:CachedImage.ErrorPlaceholder>
<OnPlatform x:TypeArguments="ImageSource">
<On Platform="iOS, Android" Value="noimage" />
<On Platform="UWP" Value="Assets/noimage.png" />
</OnPlatform>
</ffimageloading:CachedImage.ErrorPlaceholder>
</ffimageloading:CachedImage>
Элемент CachedImage
управления задает LoadingPlaceholder
и ErrorPlaceholder
свойства для образов, зависящих от платформы. Свойство LoadingPlaceholder
указывает изображение, которое будет отображаться при извлечении изображения, указанного Source
свойством, и ErrorPlaceholder
свойство указывает, что изображение должно отображаться, если при попытке получить изображение, указанное Source
свойством, возникает ошибка.
Как подразумевает имя, CachedImage
элемент управления кэширует удаленные образы на устройстве в течение времени, указанного CacheDuration
значением свойства. Если это значение свойства не задано явным образом, применяется значение по умолчанию 30 дней.
Повышение устойчивости
Все приложения, взаимодействующие с удаленными службами и ресурсами, должны быть чувствительны к временным сбоям. Временные ошибки включают временную потерю сетевого подключения к службам, временную недоступность службы или время ожидания, возникающие при занятой службе. Эти ошибки часто самокорректируются, и если действие повторяется после подходящей задержки, скорее всего, будет выполнено успешно.
Временные ошибки могут оказать огромное влияние на предполагаемое качество приложения, даже если оно было тщательно проверено во всех обозримых обстоятельствах. Чтобы обеспечить надежную работу приложения, которое взаимодействует с удаленными службами, оно должно выполнять все указанные ниже действия.
- Обнаружение сбоев при их возникновении и определение временных ошибок.
- Повторите операцию, если она определяет, что ошибка, скорее всего, будет временной и следить за количеством повторных попыток операции.
- Используйте соответствующую стратегию повторных попыток, которая указывает количество повторных попыток, задержку между каждой попыткой и действиями, которые необходимо предпринять после неудачной попытки.
Эта временная обработка ошибок может быть достигнута путем упаковки всех попыток доступа к удаленной службе в коде, реализующего шаблон повторных попыток.
Шаблон повторных попыток
Если приложение обнаруживает сбой при попытке отправить запрос в удаленную службу, он может справиться с ошибкой любым из следующих способов:
- Повторите операцию. Приложение может немедленно повторить неудачный запрос.
- Повторите операцию после задержки. Приложение должно ожидать подходящего периода времени, прежде чем повторить запрос.
- Отмена операции. Приложение должно отменить операцию и сообщить об исключении.
Стратегия повторных попыток должна быть настроена в соответствии с бизнес-требованиями приложения. Например, важно оптимизировать количество повторных попыток и интервал повторных попыток к попытке операции. Если операция является частью взаимодействия с пользователем, интервал повторных попыток должен быть коротким, и лишь несколько повторных попыток пытались избежать того, чтобы пользователи ждали ответа. Если операция является частью длительного рабочего процесса, при котором отмена или перезапуск рабочего процесса является дорогостоящим или временным, это позволяет ожидать больше времени между попытками и повторными попытками.
Примечание.
Агрессивная стратегия повторных попыток с минимальной задержкой между попытками и большим количеством повторных попыток может привести к снижению удаленной службы, которая выполняется близко к емкости или в емкости. Кроме того, такая стратегия повторных попыток также может повлиять на скорость реагирования приложения, если она постоянно пытается выполнить сбой операции.
Если запрос по-прежнему завершается ошибкой после ряда повторных попыток, лучше предотвратить дальнейшие запросы, поступающие к тому же ресурсу, и сообщить об ошибке. Затем после заданного периода приложение может выполнить один или несколько запросов к ресурсу, чтобы узнать, успешно ли они выполнены. Дополнительные сведения см. в статье Circuit Breaker Pattern (Шаблон прерывателя).
Совет
Никогда не применяйте механизм с бесконечными повторными попытками. Используйте ограниченное число повторных попыток или реализуйте шаблон разбиения цепи, чтобы разрешить службе восстановиться.
Мобильное приложение eShopOnContainers в настоящее время не реализует шаблон повторных попыток при создании веб-запросов RESTful. Однако элемент CachedImage
управления, предоставляемый библиотекой FFImageLoading , поддерживает временную обработку ошибок путем повторной загрузки образа. Если загрузка изображений завершается сбоем, будут выполнены дальнейшие попытки. Число попыток указывается свойством RetryCount
, и повторные попытки будут возникать после задержки, указанной свойством RetryDelay
. Если эти значения свойств не заданы явным образом, их значения по умолчанию применяются : 3 для RetryCount
свойства и 250 мс для RetryDelay
свойства. Дополнительные сведения об элементе CachedImage
управления см. в разделе "Кэширование изображений".
Эталонное приложение eShopOnContainers реализует шаблон повторных попыток. Дополнительные сведения, в том числе о том, как объединить шаблон повторных попыток с HttpClient
классом, см. в разделе микрослужб .NET: архитектура для контейнерных приложений .NET.
Дополнительные сведения о шаблоне повторных попыток см. в шаблоне повторных попыток .
Шаблон прерывателя
В некоторых ситуациях ошибки могут возникать из-за ожидаемых событий, которые требуют больше времени для устранения. Эти ошибки могут варьироваться от частичной потери подключения к полному сбою службы. В таких ситуациях это бессмысленно для приложения повторить операцию, которая вряд ли будет выполнена, и вместо этого следует принять, что операция завершилась ошибкой и обработать этот сбой соответствующим образом.
Шаблон разбиения цепи может предотвратить повторную попытку выполнения операции, которая, скорее всего, завершится ошибкой, а также позволяет приложению определить, была ли устранена ошибка.
Примечание.
Назначение шаблона автоматического останова отличается от шаблона повторных попыток. Шаблон повторных попыток позволяет приложению повторить операцию в ожидании успешного выполнения. Шаблон разбиения цепи запрещает приложению выполнять операцию, которая, скорее всего, завершится ошибкой.
Автоматическое выключение действует в качестве прокси-сервера операций, которые могут завершиться со сбоем. Прокси-сервер должен отслеживать количество недавних сбоев, которые произошли, и использовать эту информацию, чтобы решить, разрешать ли операция продолжаться, или немедленно возвращать исключение.
Мобильное приложение eShopOnContainers в настоящее время не реализует шаблон разбиения цепи. Однако eShopOnContainers делает. Дополнительные сведения см. в разделе микрослужб .NET: архитектура для контейнерных приложений .NET.
Совет
Объедините шаблоны повторных попыток и разбиения цепи. Приложение может объединить шаблоны повторных попыток и разбиения цепи с помощью шаблона повторных попыток для вызова операции через разбиение цепи. Однако логика повторения должна быть чувствительной к любым исключениям, возвращаемым автоматическим выключением, и отказываться от повторных попыток, если автоматическое выключение указывает, что неисправность не является временной.
Дополнительные сведения о шаблоне разбиения цепи см. в шаблоне разбиения цепи.
Итоги
Многие современные веб-решения используют веб-службы, размещенные на веб-серверах, для обеспечения функциональности удаленных клиентских приложений. Операции, предоставляемые веб-службой, представляют собой веб-API, и клиентские приложения должны иметь возможность использовать веб-API, не зная, как реализуются данные или операции, предоставляемые API.
Производительность приложения можно улучшить, кэширование часто доступных данных для быстрого хранения, расположенного рядом с приложением. Приложения могут реализовать кэширование с помощью шаблона кэширования в сторону кэша. Этот шаблон определяет, находится ли элемент в кэше. Если элемент не находится в кэше, он считывается из хранилища данных и добавляется в кэш.
При взаимодействии с веб-API приложения должны быть чувствительны к временным сбоям. Временные ошибки включают временную потерю сетевого подключения к службам, временную недоступность службы или время ожидания, возникающие при занятой службе. Эти ошибки часто самовосправляются, и если действие повторяется после подходящей задержки, то, скорее всего, это успешно. Поэтому приложения должны упаковать все попытки доступа к веб-API в коде, который реализует временный механизм обработки ошибок.