Доступ к удаленным данным

Примечание.

Эта электронная книга была опубликована весной 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 используется для управления процессом извлечения данных из микрослужбы каталога. В методе RegisterDependenciesViewModelLocator в классе CatalogService класс регистрируется в качестве сопоставления типов с ICatalogService типом с контейнером внедрения зависимостей Autofac. Затем, когда создается экземпляр CatalogViewModel класса, его конструктор принимает ICatalogService тип, который разрешает Autofac, возвращая экземпляр CatalogService класса. Дополнительные сведения о внедрении зависимостей см. в разделе "Введение в внедрение зависимостей".

На рисунке 10-1 показано взаимодействие классов, которые считывают данные каталога из микрослужбы каталога для отображения данными CatalogViewкаталога.

Retrieving data from the catalog microservice

Рис. 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.GetAsyncItems метода в классе вызывается метод в RequestProviderCatalogController классе в проекте 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 используется для управления процессом извлечения и обновления данных с помощью микрослужбы корзины. В методе RegisterDependenciesViewModelLocator в классе BasketService класс регистрируется в качестве сопоставления типов с IBasketService типом с контейнером внедрения зависимостей Autofac. Затем, когда создается экземпляр BasketViewModel класса, его конструктор принимает IBasketService тип, который разрешает Autofac, возвращая экземпляр BasketService класса. Дополнительные сведения о внедрении зависимостей см. в разделе "Введение в внедрение зависимостей".

На рис. 10-2 показано взаимодействие классов, отправляющих данные корзины, отображаемые BasketViewмикрослужбой корзины.

Sending data to the basket microservice

Рис. 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.PostAsyncPost метода в классе вызывается метод в RequestProviderBasketController классе в проекте 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

Deleteing data from the basket microservice

Рис. 10-3. Удаление данных из микрослужбы корзины

При вызове CheckoutAsync процесса проверка out вызывается метод в 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.DeleteAsyncDelete метода в классе вызывается метод в RequestProviderBasketController классе в проекте 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 в коде, который реализует временный механизм обработки ошибок.