Compartilhar via


Acesso a dados remotos

Dica

Esse conteúdo é um trecho do livro eletrônico, Padrões de Aplicativo Empresarial Usando .NETMAUI, disponível em .NET Docs ou em PDF para download gratuito que pode ser lido off-line.

Miniatura da capa do livro eletrônico MAUI Padrões de aplicativo empresarial usando .NET.

Muitas soluções modernas baseadas na Web usam serviços Web, hospedados por servidores Web, para fornecer funcionalidades para aplicativos de cliente remoto. As operações que um serviço Web expõe constituem uma API da Web.

Os aplicativos cliente devem conseguir usar a API Web sem saber como os dados ou as operações expostas pela API são implementadas. Isso requer que a API opere em conformidade com padrões comuns que permitem que um serviço Web e aplicativos cliente concordem sobre quais formatos de dados usar e a estrutura dos dados que são trocados entre aplicativos cliente e o serviço Web.

Introdução à Transferência de Estado Representacional

REST (Transferência de Estado Representacional) é um estilo arquitetural para a criação de sistemas distribuídos com base em hipermídia. Uma vantagem principal do modelo REST é que ele é baseado em padrões abertos e não vincula a implementação do modelo ou os aplicativos cliente que o acessam a nenhuma implementação específica. Portanto, um serviço Web REST pode ser implementado usando o Microsoft ASP.NET Core e os aplicativos cliente podem ser desenvolvidos usando qualquer linguagem e conjunto de ferramentas que possam gerar solicitações HTTP e analisar respostas HTTP.

O modelo de REST usa um esquema de navegação para representar objetos e serviços em uma rede, mencionados como funcionalidades. Sistemas que implementam REST geralmente usam o protocolo HTTP para transmitir solicitações para acessar esses recursos. Nesses sistemas, um aplicativo cliente envia uma solicitação na forma de um URI que identifica um recurso e um método HTTP (como GET, POST, PUT ou DELETE) que indica a operação a ser executada nesse recurso. O corpo da solicitação HTTP contém quaisquer dados necessários para executar a operação.

Observação

REST define um modelo de solicitação sem estado. Portanto, as solicitações HTTP devem ser independentes e podem ocorrer em qualquer ordem.

A resposta de uma solicitação REST usa códigos de status HTTP padrão. Por exemplo, uma solicitação que retorna dados válidos deve incluir o código de resposta HTTP 200 (OK), enquanto uma solicitação que não consegue localizar ou excluir um recurso especificado deve retornar uma resposta que inclui o código de status HTTP 404 (Not Found).

Uma API Web RESTful expõe um conjunto de recursos conectados e fornece as principais operações que permitem que um aplicativo manipule esses recursos e navegue facilmente entre eles. Por esse motivo, os URIs que constituem uma API da Web RESTful típica são orientados para os dados que ela expõe, além de usar os recursos fornecidos pelo HTTP para realizar operações com esses dados.

Os dados incluídos por um aplicativo cliente em uma solicitação HTTP e as mensagens de resposta correspondentes do servidor da Web podem ser apresentados em vários formatos, conhecidos como tipos de mídia. Quando um aplicativo cliente envia uma solicitação que retorna dados no corpo de uma mensagem ele pode especificar, no cabeçalho Accept da solicitação, os tipos de mídia com os quais pode lidar. Se o servidor Web oferece suporte a esse tipo de mídia, ele pode enviar uma resposta que inclui o cabeçalho Content-Type, que especifica o formato dos dados no corpo da mensagem. É responsabilidade do aplicativo cliente analisar a mensagem de resposta e interpretar os resultados no corpo da mensagem adequadamente.

Para obter mais informações sobre REST, confira Design de API e Implementação de API no Microsoft Docs.

Consumo de APIs RESTful

O aplicativo multiplataforma eShop usa o padrão Model-View-ViewModel (MVVM), e os elementos do modelo do padrão representam as entidades de domínio usadas no aplicativo. As classes de controlador e repositório no aplicativo de referência eShop aceitam e retornam muitos desses objetos de modelo. Portanto, eles são usados como DTOs (objetos de transferência de dados) que contêm todos os dados passados entre o aplicativo e os microsserviços em contêineres. O principal benefício de usar DTOs para passar e receber dados de um serviço Web é que, ao transmitir mais dados em uma única chamada remota, o aplicativo pode reduzir o número de chamadas que precisam ser feitas.

Como fazer solicitações da Web

O aplicativo multiplataforma eShop usa a classe HttpClient para fazer solicitações HTTP, com JSON sendo usado como o tipo de mídia. Essa classe fornece funcionalidade para enviar solicitações e receber respostas HTTP de maneira assíncrona um recurso identificado por URI. A classe HttpResponseMessage representa uma mensagem de resposta HTTP recebida de uma API REST após uma solicitação HTTP ter sido feita. Ela contém informações sobre a resposta, incluindo o código de status, cabeçalhos e qualquer corpo. A classe HttpContent representa o corpo HTTP e os cabeçalhos de conteúdo, como Content-Type e Content-Encoding. O conteúdo pode ser lido usando qualquer um dos métodos de ReadAs, como ReadAsStringAsync e ReadAsByteArrayAsync, dependendo do formato dos dados.

Como fazer uma solicitação GET

A classe CatalogService é usada para gerenciar o processo de recuperação de dados do microsserviço de catálogo. No método RegisterViewModels na classe MauiProgram, a classe CatalogService é registrado como um mapeamento de tipo ICatalogService em relação ao tipo com o contêiner de injeção de dependência. Então, quando uma instância da classe CatalogViewModel é criada, seu construtor aceita um ICatalogService type, que o contêiner de injeção de dependência resolve, retornando uma instância da classe CatalogService. Para obter mais informações sobre injeção de dependência, confira Injeção de dependência.

A imagem abaixo mostra a interação de classes que leem dados correspondentes do microsserviço de catálogo para exibição pelo CatalogView.

Como recuperar dados do microsserviço de catálogo.

Quando o CatalogView é navegado, o método OnInitialize na classe CatalogViewModel é chamado. Esse método recupera dados correspondentes do microsserviço de catálogo, conforme demonstrado no exemplo de código a seguir:

public override async Task InitializeAsync()
{
    Products = await _productsService.GetCatalogAsync();
} 

Esse método chama o método GetCatalogAsync da instância de CatalogService que foi injetada em CatalogViewModel pelo contêiner de injeção de dependência. O seguinte exemplo de código mostra o método 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;          
} 

Esse método cria o URI que identifica o recurso para o qual a solicitação será enviada e usa a classe RequestProviderpara invocar o método HTTP GET no recurso, antes de retornar os resultados para o CatalogViewModel. A classe RequestProvider contém a funcionalidade que envia uma solicitação na forma de um URI que identifica um recurso, um método HTTP que indica a operação a ser executada nesse recurso e um corpo que contém todos os dados necessários para executar a operação. Para obter informações sobre como a classe RequestProvider é injetada na classe CatalogService, confira Injeção de dependência.

O exemplo de código a seguir mostra o método GetAsync na classe RequestProvider:

public async Task<TResult> GetAsync<TResult>(string uri, string token = "")
{
    HttpClient httpClient = GetOrCreateHttpClient(token);
    HttpResponseMessage response = await httpClient.GetAsync(uri);

    await HandleResponse(response);
    TResult result = await response.Content.ReadFromJsonAsync<TResult>();

    return result;
}

Esse método chama o método GetOrCreateHttpClient, que retorna uma instância da classe HttpClient com os cabeçalhos apropriados definidos. Então, ele envia uma solicitação de GET assíncrona para o recurso identificado pelo URI, com a resposta sendo armazenada na instância HttpResponseMessage. O método HandleResponse é invocado, o que lança uma exceção se a resposta não incluir um código de status HTTP de sucesso. A resposta então é lida como uma cadeia de caracteres, convertida de JSON para um objeto de CatalogRoot e retornada para o CatalogService.

O método GetOrCreateHttpClient é mostrado no seguinte exemplo de código:

private readonly Lazy<HttpClient> _httpClient =
    new Lazy<HttpClient>(
        () =>
        {
            var httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            return httpClient;
        },
        LazyThreadSafetyMode.ExecutionAndPublication);

private HttpClient GetOrCreateHttpClient(string token = "")
    {
        var httpClient = _httpClient.Value;

        if (!string.IsNullOrEmpty(token))
        {
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        }
        else
        {
            httpClient.DefaultRequestHeaders.Authorization = null;
        }

        return httpClient;
    }

Esse método usa cria uma nova ou recupera uma instância em cache da classe HttpClient e define o cabeçalho Accept de todas as solicitações feitas pela instância HttpClient como application/json, o que indica que ele espera que o conteúdo de qualquer resposta seja formatado usando JSON. Então, se um token de acesso foi passado como um argumento para o método GetOrCreateHttpClient, ele é adicionado ao cabeçalho Authorization de todas as solicitações feitas pela instância HttpClient, prefixado com a cadeia de caracteres Bearer. Para obter mais informações sobre autorização, confira Autorização.

Dica

É altamente recomendável armazenar em cache e reutilizar instâncias do HttpClient para melhorar o desempenho do aplicativo. Criar um novo HttpClient para cada operação pode levar a um problema de esgotamento do soquete. Para obter mais informações, confira Instanciação de HttpClient no Centro de Desenvolvedores do Microsoft.

Quando o método GetAsync na classe RequestProvider chama HttpClient.GetAsync, o método Items na classe CatalogController no projeto Catalog.API é invocado, o que é mostrado no exemplo de código a seguir:

[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);
}

Esse método recupera os dados de catálogo do banco de dados SQL usando EntityFramework, e os retorna como uma mensagem de resposta que inclui um código de status HTTP de êxito e uma coleção de instâncias formatadas CatalogItem em JSON.

Como fazer uma solicitação POST

A classe BasketService é usada para gerenciar o processo de recuperação e atualização de dados com o microsserviço de cesta. No método RegisterAppServices da classe MauiProgram, a classe BasketService é registrada como um mapeamento de tipo em relação ao tipo IBasketService com o contêiner de injeção de dependência. Então, quando uma instância da classe BasketViewModel é criada, seu construtor aceita um tipo IBasketService, que o contêiner de injeção de dependência resolve, retornando uma instância da classe BasketService. Para obter mais informações sobre injeção de dependência, confira Injeção de dependência.

A imagem abaixo mostra a interação das classes que enviam os dados da cesta exibidos pelo BasketView para o microsserviço de cesta.

Como enviar dados para o microsserviço da cesta.

Quando um item é adicionado à cesta de compras, o método ReCalculateTotalAsync na classe BasketViewModel é chamado. Esse método atualiza o valor total dos itens na cesta e envia esses dados para o microsserviço da cesta, conforme demonstrado no exemplo de código a seguir:

private async Task ReCalculateTotalAsync()
{
    // Omitted for brevity...

    await _basketService.UpdateBasketAsync(
        new CustomerBasket
        {
            BuyerId = userInfo.UserId, 
            Items = BasketItems.ToList()
        }, 
        authToken);
}

Esse método chama o método UpdateBasketAsync da instância de BasketService que foi injetada em BasketViewModel pelo contêiner de injeção de dependência. O método a seguir mostra o método 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;
}

Esse método cria o URI que identifica o recurso para o qual a solicitação será enviada e usa a classe RequestProviderpara invocar o método HTTP POST no recurso, antes de retornar os resultados para o BasketViewModel. Observe que um token de acesso, obtido de IdentityServer durante o processo de autenticação, é necessário para autorizar solicitações ao microsserviço da cesta. Para obter mais informações sobre autorização, confira Autorização.

O exemplo de código a seguir mostra um dos métodos PostAsync da classe RequestProvider:

public async Task<TResult> PostAsync<TResult>(
    string uri, TResult data, string token = "", string header = "")
{
    HttpClient httpClient = GetOrCreateHttpClient(token);

    var content = new StringContent(JsonSerializer.Serialize(data));
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    HttpResponseMessage response = await httpClient.PostAsync(uri, content);

    await HandleResponse(response);
    TResult result = await response.Content.ReadFromJsonAsync<TResult>();
    
    return result;
}

Esse método chama o método GetOrCreateHttpClient, que retorna uma instância da classe HttpClient com os cabeçalhos apropriados definidos. Ele então envia uma solicitação POST assíncrona para o recurso identificado pelo URI, com os dados serializados da cesta enviados no formato JSON e a resposta armazenada na instância HttpResponseMessage. O método HandleResponse é invocado, o que lança uma exceção se a resposta não incluir um código de status HTTP de sucesso. A resposta então é lida como uma cadeia de caracteres, convertida de JSON em um objeto CustomerBasket e retornada ao BasketService. Para obter mais informações sobre o método GetOrCreateHttpClient, confira Como fazer uma solicitação GET.

Quando o método PostAsync na classe RequestProvider chama HttpClient.PostAsync, o método Post na classe BasketController no projeto Basket.API é invocado, o que é mostrado no exemplo de código a seguir:

[HttpPost]
public async Task<IActionResult> Post([FromBody] CustomerBasket value)
{
    var basket = await _repository.UpdateBasketAsync(value);
    return Ok(basket);
} 

Esse método usa uma instância da classe RedisBasketRepository para manter os dados da cesta no cache Redis e os retorna como uma mensagem de resposta que inclui um código de status HTTP de sucesso e uma instância CustomerBasket formatada em JSON.

Como fazer uma solicitação DELETE

A imagem abaixo mostra as interações de classes que excluem os dados do microsserviço de cesta para o CheckoutView.

Como excluir dados do microsserviço da cesta.

Quando o processo de check-out é invocado, o método CheckoutAsync na classe CheckoutViewModel é chamado. Este método cria um novo pedido antes de limpar a cesta de compras, conforme demonstrado no exemplo de código a seguir:

private async Task CheckoutAsync()
{
    // Omitted for brevity...

    await _basketService.ClearBasketAsync(
        _shippingAddress.Id.ToString(), authToken);
}

Esse método chama o método ClearBasketAsync da instância de BasketService que foi injetada em CheckoutViewModel pelo contêiner de injeção de dependência. O método a seguir mostra o método ClearBasketAsync:

public async Task ClearBasketAsync(string guidUser, string token)
{
    UriBuilder builder = new(GlobalSetting.Instance.BasketEndpoint);
    builder.Path = guidUser;
    string uri = builder.ToString();
    await _requestProvider.DeleteAsync(uri, token);
}

Esse método cria o URI que identifica o recurso para o qual a solicitação será enviada e usa a classe RequestProvider para invocar o método HTTP DELETE no recurso. Observe que um token de acesso, obtido de IdentityServer durante o processo de autenticação, é necessário para autorizar solicitações ao microsserviço da cesta. Para obter mais informações sobre autorização, confira Autorização.

O exemplo de código a seguir mostra o método DeleteAsync na classe RequestProvider:

public async Task DeleteAsync(string uri, string token = "")
{
    HttpClient httpClient = GetOrCreateHttpClient(token);
    await httpClient.DeleteAsync(uri);
}

Esse método chama o método GetOrCreateHttpClient, que retorna uma instância da classe HttpClient com os cabeçalhos apropriados definidos. Em seguida, ele envia uma de DELETE solicitação assíncrona para o recurso identificado pelo URI. Para obter mais informações sobre o método GetOrCreateHttpClient, confira Como fazer uma solicitação GET.

Quando o método DeleteAsync na classe RequestProvider chama HttpClient.DeleteAsync, o método Delete na classe BasketController no projeto Basket.API é invocado, o que é mostrado no exemplo de código a seguir:

[HttpDelete("{id}")]
public void Delete(string id) =>
    _repository.DeleteBasketAsync(id);

Esse método usa uma instância da classe RedisBasketRepository para excluir os dados da cesta do cache Redis.

Cache de dados

O desempenho de um aplicativo pode ser melhorado transferindo para cache dados acessados com frequência no armazenamento rápido localizado próximo ao aplicativo. Se o armazenamento rápido estiver localizado mais próximo do aplicativo do que da fonte original, o armazenamento em cache pode melhorar significativamente os tempos de resposta na recuperação de dados.

A forma mais comum de cache é o de leitura, em que um aplicativo recupera dados referenciando o cache. Se os dados não estiverem no cache, ele é recuperado do armazenamento de dados e adicionado ao cache. Os aplicativos podem implementar o cache de leitura com o padrão cache-aside. Esse padrão determina se o item está atualmente no cache. Se os item não estiver no cache, ele será recuperado do armazenamento de dados e adicionado a ele. Para obter mais informações, confira o padrão Cache-Aside no Microsoft Docs.

Dica

Armazenar dados em cache que são lidos com frequência e são alterados com pouca frequência.

Os dados poderão ser adicionados ao cache sob demanda na primeira vez em que forem recuperados por um aplicativo. Isso significa que o aplicativo precisa buscar os dados apenas uma vez no armazenamento de dados e o acesso subsequente pode ser atendido pelo uso do cache.

Os aplicativos distribuídos, como o aplicativo de referência eShop, devem fornecer um ou ambos os caches a seguir:

  • Um cache compartilhado, que pode ser acessado por vários processos ou computadores.
  • Um cache privado, em que os dados são mantidos localmente no dispositivo que executa o aplicativo.

O aplicativo multiplataforma eShop usa um cache privado, em que os dados são mantidos localmente no dispositivo que está executando uma instância do aplicativo.

Dica

Pense no cache como um armazenamento de dados transitório que pode desaparecer a qualquer momento.

Verifique se os dados são mantidos no armazenamento de dados original, bem como no cache. As chances de perda de dados serão minimizadas se o cache ficar indisponível.

Gerenciamento de expiração de dados

É impraticável esperar que os dados armazenados em cache sempre sejam consistentes com os dados originais. Dados em armazenamentos originais podem ser alterados depois do armazenamento em cache, fazendo com que os dados em cache se tornem obsoletos. Portanto, os aplicativos devem implementar uma estratégia que ajude a garantir que os dados no cache sejam tão atualizados quanto possível, mas também possam detectar e lidar com situações que possam surgir quando os dados no cache se tornarem obsoletos. A maioria dos mecanismos de cache permite que ele seja configurado de modo que os dados expirem, reduzindo, portanto, o potencial período de desatualização dos dados.

Dica

Defina um tempo de expiração padrão ao configurar um cache.

Muitos caches implementam a expiração, que invalida os dados e os remove do cache se não forem acessados por um período especificado. No entanto, é necessário ter cuidado ao escolher o período de expiração. Se for muito curto, os dados expirarão muito rapidamente e os benefícios do cache serão reduzidos. Se for muito longo, os dados poderão ficar obsoletos. Portanto, o tempo de expiração deve corresponder ao padrão de acesso em que os aplicativos usam os dados.

Quando os dados armazenados em cache expiram, eles devem ser removidos do cache, e o aplicativo deve recuperá-los do armazenamento de dados original e colocá-los novamente no cache.

Também é possível que um cache fique cheio se os dados permanecerem por um período muito longo. Portanto, as solicitações para adicionar novos itens ao cache podem ser necessárias para remover alguns itens em um processo conhecido como eviction. Os serviços de cache geralmente despejam os dados usados menos recentemente. No entanto, existem outras políticas de remoção, incluindo usados mais recentemente e saída por ordem de entrada. Para obter mais informações, confira Diretrizes de Cache no Microsoft Docs.

Armazenar imagens em cache

O aplicativo multiplataforma eShop consome imagens de produtos remotos que se beneficiam do armazenamento em cache. Essas imagens são exibidas pelo controle Imagem. O controle de imagem MAUI .NET oferece suporte ao cache de imagens baixadas por padrão e armazena a imagem localmente por 24 horas. Além disso, o tempo de expiração pode ser configurado com a propriedade CacheValidity. Para obter mais informações, confira Cache de imagem baixada no Centro de Desenvolvedores do Microsoft.

Aumento da resiliência

Todos os aplicativos que se comunicam com serviços e recursos remotos são suscetíveis a falhas transitórias. As falhas transitórias incluem a perda momentânea da conectividade de rede e serviços, a indisponibilidade temporária de um serviço ou tempos limite que surgem quando um serviço está ocupado. Essas falhas geralmente são corrigidas automaticamente. Se a ação for repetida após um tempo razoável, é provável que seja bem-sucedida.

As falhas transitórias podem ter um enorme impacto na qualidade percebida de um aplicativo, mesmo que ele tenha sido integralmente testado sob todas as circunstâncias previsíveis. Para garantir que um aplicativo que se comunique com serviços remotos opere de forma confiável, ele deve ser capaz de fazer o seguinte:

  • Detectar falhas quando elas ocorrem e determine se as falhas provavelmente serão transitórias.
  • Repetir a operação se for determinado que a falha provavelmente será transitória e acompanhar o número de vezes que a operação foi repetida.
  • Usar uma estratégia de repetição apropriada, que especifique o número de tentativas, o atraso entre cada tentativa e as ações a serem executadas após uma tentativa com falha.

Esse tratamento de falha transitória pode ser obtido encapsulando todas as tentativas de acessar um serviço remoto no código que implementa o padrão de repetição.

Padrão de repetição

Se um aplicativo detectar uma falha ao tentar enviar uma solicitação para um serviço remoto, ele poderá lidar com a falha de uma das seguintes maneiras:

  • Repetindo a operação. O aplicativo pode repetir a solicitação com falha imediatamente.
  • Repetindo a operação após um atraso. O aplicativo deve esperar por um tempo adequado antes de tentar executar novamente a solicitação.
  • Cancelando a operação. O aplicativo deve cancelar a operação e relatar uma exceção.

A estratégia de repetição deve ser ajustada para corresponder às demandas comerciais do aplicativo. Por exemplo, é importante otimizar a contagem de repetições e o intervalo de repetição para a operação que está sendo tentada. Se a operação fizer parte de uma interação do usuário, o intervalo de repetição deve ser curto e ter apenas algumas tentativas para evitar que os usuários esperem por uma resposta. Se a operação fizer parte de um fluxo de trabalho de execução prolongada, onde cancelar ou reiniciar o fluxo de trabalho for caro ou demorado, é apropriado esperar mais tempo entre as tentativas e repetir mais vezes.

Observação

Uma estratégia de repetição agressiva com atraso mínimo entre as tentativas e um grande número de tentativas pode degradar um serviço remoto que está sendo executado próximo ou no limite da capacidade. Adicionalmente, essa estratégia de repetição também pode afetar a capacidade de resposta do aplicativo se ele estiver tentando executar uma operação com falha de maneira contínua.

Se uma solicitação ainda falhar após várias tentativas, é melhor para o aplicativo impedir que outras solicitações sejam enviadas para o mesmo recurso e relatar uma falha. Então, após um período definido, o aplicativo pode fazer uma ou mais solicitações ao recurso para verificar se houve sucesso na tentativa. Para obter mais informações, confira Padrão do disjuntor.

Dica

Nunca implemente um mecanismo de repetição infinita. Alternativamente, prefira uma retirada exponencial.

Use um número finito de novas tentativas ou implemente o padrão como Disjuntor para permitir a recuperação de um serviço.

O aplicativo de referência eShop implementa o padrão de repetição.

Para obter mais informações sobre o padrão de repetição, confira o padrão de Repetição no Microsoft Docs.

Padrão de disjuntor

Em algumas situações, falhas podem ocorrer devido a eventos previstos que levam mais tempo para serem corrigidos. Essas falhas podem variar de uma perda parcial de conectividade até a falha completa de um serviço. Nessas situações, aplicativo tentar novamente uma operação que provavelmente não será bem-sucedida será inútil e, alternativamente, ele deve aceitar que a operação falhou e lidar com essa falha de acordo.

O padrão do disjuntor pode impedir que um aplicativo tente executar uma operação com probabilidade de falha repetidamente, além de permitir que o aplicativo detecte se a falha foi resolvida.

Observação

A finalidade do padrão do disjuntor é diferente do padrão de repetição. O padrão de Repetição permite que um aplicativo volte a tentar executar uma operação na expectativa que haverá êxito. O padrão do disjuntor impede que um aplicativo execute uma operação que provavelmente falhará.

Um disjuntor atua como um proxy para operações que podem falhar. O proxy deve monitorar o número de falhas recentes ocorridas e usar essas informações para decidir se deve permitir que a operação continue ou retorne uma exceção imediatamente.

O aplicativo multiplataforma eShop não implementa atualmente o padrão de disjuntor. No entanto, o eShop o faz.

Dica

Combine os padrões de repetição e do disjuntor.

Um aplicativo pode combinar os padrões de repetição e do disjuntor usando o padrão de repetição para invocar uma operação por meio de um disjuntor. No entanto, a lógica de repetição deverá ser sensível às exceções retornadas pelo disjuntor e abandonar as novas tentativas se o disjuntor indicar que uma falha não é transitória.

Para obter mais informações sobre o padrão do disjuntor, acesse o Microsoft Docs e procure padrão do Disjuntor.

Resumo

Muitas soluções modernas baseadas na Web usam serviços Web, hospedados por servidores Web, para fornecer funcionalidades para aplicativos de cliente remoto. As operações que um serviço Web expõe constituem uma API Web, e os aplicativos cliente devem conseguir usar a API Web sem saber como os dados ou operações que a API expõe são implementados.

O desempenho de um aplicativo pode ser melhorado transferindo para cache dados acessados com frequência no armazenamento rápido localizado próximo ao aplicativo. Os aplicativos podem implementar o cache de leitura com o padrão cache-aside. Esse padrão determina se o item está atualmente no cache. Se os item não estiver no cache, ele será recuperado do armazenamento de dados e adicionado a ele.

Ao se comunicar com APIs Web, os aplicativos devem conseguir detectar falhas transitórias. As falhas transitórias incluem a perda momentânea da conectividade de rede e serviços, a indisponibilidade temporária de um serviço ou tempos limite que surgem quando um serviço está ocupado. Essas falhas geralmente são corrigidas automaticamente. Se a ação for repetida após um tempo razoável, é provável que seja bem-sucedida. Portanto, os aplicativos devem encapsular todas as tentativas de acessar uma API Web no código que implementa um mecanismo transitório de tratamento de falhas.