Acceso a datos remotos
Sugerencia
Este contenido es un extracto del libro electrónico "Patrones de aplicaciones empresariales con .NET MAUI", disponible en Documentación de .NET o como un PDF descargable y gratuito que se puede leer sin conexión.
Muchas soluciones modernas basadas en web hacen uso de servicios web, hospedados en servidores web, para proporcionar funcionalidad a las aplicaciones cliente remotas. Las operaciones que expone un servicio web constituyen una API web.
Las aplicaciones cliente deben tener la capacidad de usar la API web sin saber cómo se implementan los datos o las operaciones que expone la API. Para ello, se requiere que la API se rija por las normas comunes que permiten que una aplicación cliente y un servicio web acuerden qué formatos de datos se usan y la estructura de los datos que se intercambian entre las aplicaciones cliente y el servicio web.
Introducción a la transferencia de estado representacional
La Transferencia de estado representacional (REST) es un estilo de arquitectura para la creación de sistemas distribuidos basados en hipermedia. Una de las principales ventajas del modelo de REST es que se basa en estándares abiertos y no vincula la implementación del modelo o las aplicaciones cliente que tienen acceso a él con ninguna implementación específica. Por tanto, un servicio web REST podría implementarse mediante Microsoft ASP.NET Core, y las aplicaciones cliente podrían desarrollarse usando cualquier lenguaje y conjunto de herramientas que pueda generar solicitudes HTTP y analizar las respuestas HTTP.
El modelo REST usa un esquema de navegación para representar objetos y servicios en una red, denominados recursos. Los sistemas que implementan REST normalmente usan el protocolo HTTP para transmitir solicitudes de acceso a estos recursos. En estos sistemas, una aplicación cliente envía una solicitud en forma de un URI que identifica un recurso y un método HTTP (como GET, POST, PUT o DELETE) que indica la operación que se realizará en ese recurso. El cuerpo de la solicitud HTTP contiene todos datos necesarios para realizar la operación.
Nota
REST define un modelo de solicitud sin estado. Por lo tanto, las solicitudes HTTP deben ser independientes y pueden producirse en cualquier orden.
La respuesta de una solicitud REST hace uso de códigos de estado HTTP estándar. Por ejemplo, una solicitud que devuelve datos válidos debe incluir el código de respuesta HTTP 200 (OK
), mientras que una solicitud que no encuentra o elimina un recurso especificado debe devolver una respuesta que incluya el código de estado HTTP 404 (Not Found
).
Una API web RESTful expone un conjunto de recursos conectados y proporciona las operaciones básicas que permiten a una aplicación manipular esos recursos y navegar fácilmente entre ellos. Por este motivo, los URI que constituyen una API web RESTful típica están orientados a los datos que dicha API expone y usan las funciones proporcionadas por HTTP para operar con estos datos.
Los datos incluidos por una aplicación cliente en una solicitud HTTP, y los mensajes de respuesta correspondientes del servidor web, podrían presentarse en una variedad de formatos, conocidos como tipos de medios. Cuando una aplicación cliente envía una solicitud que devuelve datos en el cuerpo de un mensaje, puede especificar los tipos de medios que puede controlar en el encabezado Accept de la solicitud. Si el servidor web admite este tipo de medio, puede responder con una respuesta que incluye el encabezado Content-Type que especifica el formato de los datos en el cuerpo del mensaje. Es responsabilidad de la aplicación cliente analizar el mensaje de respuesta e interpretar correctamente los resultados en el cuerpo del mensaje.
Para más información sobre REST, consulte Diseño de API e Implementación de API en Microsoft Docs.
Consumo de API de RESTful
La aplicación multiplataforma eShop usa el patrón Modelo-Vista-Modelo de vista (MVVM), y los elementos del modelo del patrón representan las entidades de dominio usadas en la aplicación. Las clases de controlador y repositorio de la aplicación de referencia eShop aceptan y devuelven muchos de estos objetos de modelo. Por lo tanto, se usan como objetos de transferencia de datos (DTO) que contienen todos los datos que se pasan entre la aplicación y los microservicios contenedorizados. La principal ventaja de usar DTO para pasar y recibir datos a y desde un servicio web es que, al transmitir más datos en una sola llamada remota, la aplicación puede reducir el número de llamadas remotas que se deben realizar.
Realización de las solicitudes web
La aplicación multiplataforma eShop usa la clase HttpClient
para realizar solicitudes a través de HTTP, con la utilización de JSON como tipo de medio. Esta clase proporciona funcionalidad para enviar solicitudes HTTP de forma asincrónica y recibir respuestas HTTP de un recurso identificado por URI. La clase HttpResponseMessage representa un mensaje de respuesta HTTP recibido de una API de REST una vez realizada una solicitud HTTP. Contiene información sobre la respuesta, incluido el código de estado, los encabezados y cualquier cuerpo. La clase HttpContent representa el cuerpo HTTP y los encabezados de contenido, como Content-Type y Content-Encoding. El contenido se puede leer mediante cualquiera de los métodos ReadAs
, como ReadAsStringAsync
y ReadAsByteArrayAsync
, según el formato de los datos.
Realización de una solicitud GET
La clase CatalogService
se usa para administrar el proceso de recuperación de datos desde el microservicio de catálogo. En el método RegisterViewModels
de la clase MauiProgram
, la clase CatalogService
se registra como una asignación de tipos con el tipo ICatalogService
con el contenedor de inserción de dependencias. A continuación, cuando se crea una instancia de la clase CatalogViewModel
, su constructor acepta un objeto ICatalogService type
, que el contenedor de inserción de dependencias resuelve, y devuelve una instancia de la clase CatalogService
. Para más información sobre la inserción de dependencias, vea Inserción de dependencias.
En la imagen siguiente se muestra la interacción de las clases que leen datos de catálogo del microservicio de catálogo para su visualización mediante CatalogView.
Cuando se navega hasta CatalogView
, se llama al método OnInitialize
de la clase CatalogViewModel. Este método recupera datos de catálogo del microservicio de catálogo, como se muestra en el ejemplo de código siguiente:
public override async Task InitializeAsync()
{
Products = await _productsService.GetCatalogAsync();
}
Este método llama al método GetCatalogAsync
de la instancia CatalogService
insertada en CatalogViewModel
por el contenedor de inserción de dependencias. El siguiente ejemplo de código muestra el 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;
}
Este método compila el URI que identifica el recurso al que se enviará la solicitud y usa la clase RequestProvider
para invocar el método HTTP GET en el recurso, antes de devolver los resultados a CatalogViewModel
. La clase RequestProvider
contiene una funcionalidad que envía una solicitud en forma de URI que identifica un recurso, un método HTTP que indica la operación que se va a realizar en ese recurso y un cuerpo que contiene los datos necesarios para realizar la operación. Para obtener información sobre cómo se inserta la clase RequestProvider
en la clase CatalogService
, vea Inserción de dependencias.
En el ejemplo de código siguiente se muestra el método GetAsync
de la clase 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;
}
Este método llama al método GetOrCreateHttpClient
, que devuelve una instancia de la clase HttpClient
con los encabezados adecuados establecidos. A continuación, envía una solicitud asincrónica GET
al recurso identificado por el URI, con la respuesta almacenada en la instancia HttpResponseMessage
. A continuación, se invoca el método HandleResponse
, que produce una excepción si la respuesta no incluye un código de estado HTTP correcto. A continuación, la respuesta se lee como una cadena, se convierte de JSON en un objeto CatalogRoot
y se devuelve a CatalogService
.
El método GetOrCreateHttpClient
se muestra en el ejemplo de código siguiente:
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;
}
Este método crea una instancia o recupera una instancia almacenada en caché de la clase HttpClient
y establece el encabezado Accept de las solicitudes realizadas por la instancia HttpClient
a application/json
, lo que indica que espera que el contenido de cualquier respuesta tenga el formato JSON. A continuación, si se pasó un token de acceso como un argumento al método GetOrCreateHttpClient
, se agrega al encabezado Authorization
de las solicitudes realizadas por la instancia HttpClient
, cuyo prefijo es la cadena Bearer
. Para obtener más información acerca de la autorización, vea Autorización.
Sugerencia
Es muy recomendable almacenar las instancias de HttpClient
en la caché y reutilizarlas para mejorar el rendimiento de la aplicación. La creación de un elemento HttpClient
para cada operación puede provocar un problema con el agotamiento de sockets. Para obtener más información, consulte Instanciación de HttpClient en el Centro para desarrolladores de Microsoft.
Cuando el método GetAsync
de la clase RequestProvider
llama a HttpClient.GetAsync
, se invoca el método Items
de la clase CatalogController
del proyecto Catalog.API
, que se muestra en el ejemplo de código siguiente:
[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);
}
Este método recupera los datos del catálogo de la base de datos SQL mediante EntityFramework y lo devuelve como un mensaje de respuesta que incluye un código de estado HTTP correcto y una colección de instancias CatalogItem
con formato JSON.
Realización de una solicitud POST
La clase BasketService
se usa para administrar el proceso de recuperación y actualización de datos con el microservicio de la cesta de la compra. En el método RegisterAppServices
de la clase MauiProgram
, la clase BasketService
se registra como una asignación de tipos con el tipo IBasketService
con el contenedor de inserción de dependencias. A continuación, cuando se crea una instancia de la clase BasketViewModel
, su constructor acepta un tipo IBasketService
, que el contenedor de inserción de dependencias resuelve, y devuelve una instancia de la clase BasketService
. Para más información sobre la inserción de dependencias, vea Inserción de dependencias.
En la imagen siguiente se muestra la interacción de las clases que envían los datos de la cesta de la compra mostrados por BasketView al microservicio de cesta de la compra.
Cuando se agrega un elemento a la cesta de la compra, se llama al método ReCalculateTotalAsync
de la clase BasketViewModel
. Este método actualiza el valor total de los elementos de la cesta de la compra y envía los datos de la cesta al microservicio de cesta de la compra, como se muestra en el ejemplo de código siguiente:
private async Task ReCalculateTotalAsync()
{
// Omitted for brevity...
await _basketService.UpdateBasketAsync(
new CustomerBasket
{
BuyerId = userInfo.UserId,
Items = BasketItems.ToList()
},
authToken);
}
Este método llama al método UpdateBasketAsync
de la instancia BasketService
insertada en BasketViewModel
por el contenedor de inserción de dependencias. El método siguiente muestra el 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;
}
Este método compila el URI que identifica el recurso al que se enviará la solicitud y usa la clase RequestProvider
para invocar el método HTTP POST en el recurso, antes de devolver los resultados a BasketViewModel
. Tenga en cuenta que se requiere un token de acceso obtenido de IdentityServer
durante el proceso de autenticación para autorizar las solicitudes al microservicio de cesta de la compra. Para obtener más información acerca de la autorización, vea Autorización.
En el ejemplo de código siguiente se muestra uno de los métodos PostAsync
de la clase 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;
}
Este método llama al método GetOrCreateHttpClient
, que devuelve una instancia de la clase HttpClient
con los encabezados adecuados establecidos. A continuación, envía una solicitud POST asincrónica al recurso identificado por el URI, con los datos de la cesta de la compra serializados que se envían en formato JSON y la respuesta que se almacena en la instancia HttpResponseMessage
. A continuación, se invoca el método HandleResponse
, que produce una excepción si la respuesta no incluye un código de estado HTTP correcto. A continuación, la respuesta se lee como una cadena, se convierte de JSON en un objeto CustomerBasket
y se devuelve a BasketService. Para obtener más información sobre el método GetOrCreateHttpClient
, vea Realización de una solicitud GET.
Cuando el método PostAsync
de la clase RequestProvider
llama a HttpClient.PostAsync
, se invoca el método Post
de la clase BasketController
del proyecto Basket.API
, que se muestra en el ejemplo de código siguiente:
[HttpPost]
public async Task<IActionResult> Post([FromBody] CustomerBasket value)
{
var basket = await _repository.UpdateBasketAsync(value);
return Ok(basket);
}
Este método usa una instancia de la clase RedisBasketRepository
para conservar los datos de la cesta de la compra en la caché de Redis y los devuelve como un mensaje de respuesta que incluye un código de estado HTTP correcto y una instancia CustomerBasket
con formato JSON.
Realización de una solicitud DELETE
En la imagen siguiente se muestran las interacciones de las clases que eliminan los datos de la cesta de la compra del microservicio de cesta de la compra, para CheckoutView
.
Cuando se invoca el proceso de finalización de la compra, se llama al método CheckoutAsync
de la clase CheckoutViewModel
. Este método crea un pedido, antes de vaciar la cesta de la compra, como se muestra en el ejemplo de código siguiente:
private async Task CheckoutAsync()
{
// Omitted for brevity...
await _basketService.ClearBasketAsync(
_shippingAddress.Id.ToString(), authToken);
}
Este método llama al método ClearBasketAsync
de la instancia BasketService
insertada en CheckoutViewModel
por el contenedor de inserción de dependencias. El método siguiente muestra el 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);
}
Este método compila el URI que identifica el recurso al que se enviará la solicitud y usa la clase RequestProvider
para invocar el método HTTP DELETE
en el recurso. Tenga en cuenta que se requiere un token de acceso obtenido de IdentityServer
durante el proceso de autenticación para autorizar las solicitudes al microservicio de cesta de la compra. Para obtener más información acerca de la autorización, vea Autorización.
En el ejemplo de código siguiente se muestra el método DeleteAsync
de la clase RequestProvider
:
public async Task DeleteAsync(string uri, string token = "")
{
HttpClient httpClient = GetOrCreateHttpClient(token);
await httpClient.DeleteAsync(uri);
}
Este método llama al método GetOrCreateHttpClient
, que devuelve una instancia de la clase HttpClient
con los encabezados adecuados establecidos. A continuación, envía una solicitud asincrónica DELETE
al recurso identificado por el URI. Para obtener más información sobre el método GetOrCreateHttpClient
, vea Realización de una solicitud GET.
Cuando el método DeleteAsync
de la clase RequestProvider
llama a HttpClient.DeleteAsync
, se invoca el método Delete
de la clase BasketController
del proyecto Basket.API
, que se muestra en el ejemplo de código siguiente:
[HttpDelete("{id}")]
public void Delete(string id) =>
_repository.DeleteBasketAsync(id);
Este método usa una instancia de la clase RedisBasketRepository
para eliminar los datos de la cesta de la compra de la caché de Redis.
Almacenamiento de datos en caché
El rendimiento de una aplicación se puede mejorar almacenando en la caché los datos a los que se accede con frecuencia a un almacenamiento rápido que se encuentra cerca de la aplicación. Si el almacenamiento rápido se encuentra más cerca de la aplicación que la fuente original, el almacenamiento en caché puede mejorar significativamente los tiempos de respuesta al recuperar datos.
La forma más común de almacenamiento en caché es el almacenamiento en caché de lectura, donde una aplicación recupera datos haciendo referencia a la memoria caché. Si los datos no se están en la caché, se recuperan del almacén de datos y se agregan a la caché. Las aplicaciones pueden implementar el almacenamiento en caché de lectura con el patrón cache-aside. Este patrón determina si el elemento está actualmente en la memoria caché. Si los datos no se están en la caché, se recuperan del almacén de datos y se agregan a la caché. Para obtener más información, consulte el patrón Cache-Aside en Microsoft Docs.
Sugerencia
Almacene en caché los datos que se leen con frecuencia y que cambian con poca frecuencia.
Estos datos pueden agregarse a la caché a petición la primera vez que los recupera una aplicación. Esto significa que la aplicación debe capturar los datos una sola vez del almacén de datos y que el posterior acceso se puede satisfacer mediante la caché.
Las aplicaciones distribuidas, como la aplicación de referencia eShop, deben proporcionar una de las siguientes memorias caché o ambas:
- Una caché compartida a la que pueden acceder varios procesos o máquinas.
- Una caché privada, donde los datos se mantienen localmente en el dispositivo que ejecuta la aplicación.
La aplicación multiplataforma eShop usa una caché privada, donde los datos se mantienen localmente en el dispositivo que ejecuta una instancia de la aplicación.
Sugerencia
Considere la caché como un almacén de datos transitorios que podrían desaparecer en cualquier momento.
Asegúrese de que los datos se mantienen tanto en el almacén de datos original como en la memoria caché. Las posibilidades de perder datos se minimizan si la memoria caché deja de estar disponible.
Administración de la expiración de datos
No es práctico esperar que los datos almacenados en la caché siempre sean coherentes con los datos originales. Los datos del almacén de datos original pueden cambiar después de haberse almacenado en caché, lo que hace que los datos almacenados en la memoria caché se vuelvan obsoletos. Por tanto, las aplicaciones deben implementar una estrategia que ayude a garantizar que los datos de la caché estén lo más actualizados posible, pero que también pueda detectar y tratar situaciones que surgen cuando los datos de la caché se han vuelto obsoletos. La mayoría de los mecanismos de almacenamiento en caché permiten configurar la memoria caché para que expiren los datos y, por tanto, reducir el período durante el que los datos podrían quedar obsoletos.
Sugerencia
Establezca una hora de expiración predeterminada al configurar una memoria caché.
Muchas de las memorias caché implementan una expiración que invalida los datos y los quita de la caché si no se accede a ellos durante un período especificado. Sin embargo, se debe tener cuidado al elegir el período de expiración. Si es demasiado corto, los datos expirarán demasiado rápido y se reducirán las ventajas del almacenamiento en caché. Si es demasiado largo, existe el riesgo de que los datos se queden obsoletos. Por lo tanto, la hora de expiración debe coincidir con el patrón de acceso a las aplicaciones que usan los datos.
Cuando los datos almacenados en caché expiran, se deben quitar de la memoria caché, y la aplicación debe recuperar los datos del almacén de datos original y volver a almacenarlos en la memoria caché.
También es posible que una caché se rellene si se permite que los datos permanezcan almacenados durante mucho tiempo. Por lo tanto, es posible que se requieran solicitudes para agregar nuevos elementos a la memoria caché para quitar algunos elementos en un proceso conocido como expulsión. Normalmente, los servicios de almacenamiento en caché expulsan los datos menos usados recientemente. Sin embargo, hay otras directivas de expulsión, como los menos usados recientemente o el primero en llegar, el primero en salir. Para obtener más información, vea Guía sobre el almacenamiento en caché en Microsoft Docs.
Almacenamiento en caché de imágenes
La aplicación multiplataforma eShop consume imágenes de productos remotas que se benefician de almacenarse en caché. Estas imágenes se muestran mediante el control Image. El control Image MAUI de .NET admite el almacenamiento en caché de imágenes descargadas que tiene habilitado el almacenamiento en caché de forma predeterminada y almacenará la imagen localmente durante 24 horas. Además, la hora de expiración se puede configurar con la propiedad CacheValidity. Para obtener más información, vea Almacenamiento en caché de imágenes descargadas en el Centro para desarrolladores de Microsoft.
Aumento de la resistencia
Todas las aplicaciones que se comunican con los recursos y servicios remotos deben ser sensibles a errores transitorios. Los errores transitorios incluyen la pérdida momentánea de conectividad de red a los servicios, la indisponibilidad temporal de un servicio o tiempos de espera que surgen cuando un servicio está ocupado. Estos errores suelen ser de corrección automática y, si la acción se repite después de un intervalo adecuado, es probable que se realice correctamente.
Los errores transitorios pueden tener un gran impacto en la calidad percibida de una aplicación, incluso si se ha probado exhaustivamente en todas las circunstancias previsibles. Para asegurarse de que una aplicación que se comunica con servicios remotos funciona de forma confiable, debe poder hacer todo lo siguiente:
- Detectar errores cuando se produzcan y determinar si es probable que los errores sean transitorios.
- Reintentar la operación si se determina que es posible que el error sea transitorio y realizar un seguimiento de la cantidad de veces que se vuelve a intentar la operación.
- Usar una estrategia de reintento apropiada, que especifica el número de reintentos, el intervalo entre cada intento y las acciones a realizar después de un intento fallido.
Este control de errores transitorios se puede lograr ajustando todos los intentos de acceder a un servicio remoto en el código que implementa el patrón de reintento.
Patrón Retry
Si una aplicación detecta un error al intentar enviar una solicitud a un servicio remoto, puede tratar el error de alguna de las siguientes formas:
- Reintentar la operación. La aplicación podría reintentar la solicitud con errores inmediatamente.
- Reintentar la operación después de un retraso. La aplicación debe esperar el tiempo adecuado antes de reintentar la solicitud.
- Cancelar la operación. La aplicación debe cancelar la operación e informar de una excepción.
La estrategia de reintento se debe ajustar para que coincida con los requisitos empresariales de la aplicación. Por ejemplo, es importante optimizar el número y el intervalo de reintentos en la operación que se está intentando. Si la operación forma parte de una interacción del usuario, el intervalo de reintento debe ser corto, y solo unos pocos reintentos intentan evitar que los usuarios tengan que esperar una respuesta. Si la operación forma parte de un flujo de trabajo de larga duración, donde cancelar y reiniciar el flujo de trabajo resulta lento o costoso, conviene esperar más tiempo entre intentos y efectuar más reintentos.
Nota
Una estrategia de reintentos agresiva con un retraso mínimo entre intentos, y un gran número de reintentos, podría degradar un servicio remoto que se ejecuta en su capacidad o próximo a esta. Además, dicha estrategia de reintento también podría afectar a la capacidad de respuesta de la aplicación si continuamente intenta realizar una operación con errores.
Si una solicitud sigue sin funcionar después de una serie de reintentos, lo mejor para la aplicación es impedir que las solicitudes adicionales vayan al mismo recurso y notificar un error. A continuación, después de un período establecido, la aplicación puede realizar una o varias solicitudes al recurso para ver si se realizan correctamente. Para más información, vea Patrón de disyuntor.
Sugerencia
Nunca implemente un mecanismo de reintento infinito. En su lugar, prefiere un retroceso exponencial.
Use un número finito de reintentos o implemente el patrón de Disyuntor para permitir que un servicio se recupere.
La aplicación de referencia eShop implementa el patrón de reintento.
Para obtener más información sobre el patrón de reintento, consulte el patrón Retry en Microsoft Docs.
Patrón de disyuntor
En algunas situaciones, pueden producirse errores debido a eventos anticipados que tardan más tiempo en corregirse. Estos errores pueden ir desde una pérdida parcial de conectividad hasta el fallo total del servicio. En estas situaciones, no tiene sentido que una aplicación reintente una operación que es poco probable que se realice correctamente y, en su lugar, debe aceptar que la operación ha provocado errores y tratarlos en consecuencia.
El patrón de disyuntor puede impedir que una aplicación intente ejecutar repetidamente una operación que es probable que produzca un error, al tiempo que permite a la aplicación detectar si se ha resuelto el error.
Nota
El propósito del patrón de disyuntor es diferente del patrón de reintento. El patrón Retry permite a una aplicación reintentar una operación esperando que se podrá ejecutar correctamente. El patrón de disyuntor impide que una aplicación realice una operación que es probable que tenga errores.
Un disyuntor actúa como un proxy para las operaciones que podrían producir errores. El proxy debe supervisar el número de errores recientes que se han producido y utilizar esta información para decidir si permitir que continúe la operación, o devolver de inmediato una excepción.
La aplicación multiplataforma eShop no implementa actualmente el patrón de disyuntor. Sin embargo, eShop sí.
Sugerencia
Combine los patrones de reintento y disyuntor.
Una aplicación puede combinar estos dos patrones utilizando el patrón de reintento para invocar una operación mediante un disyuntor. Sin embargo, la lógica de reintento debe tener en cuenta las excepciones devueltas por el disyuntor y dejar de reintentar la operación si este indica que un error no es transitorio.
Para obtener más información sobre el patrón de disyuntor, consulte el patrón Disyuntor en Microsoft Docs.
Resumen
Muchas soluciones modernas basadas en web hacen uso de servicios web, hospedados en servidores web, para proporcionar funcionalidad a las aplicaciones cliente remotas. Las operaciones que expone un servicio web constituyen una API web, y las aplicaciones cliente deben poder usar la API web sin saber cómo se implementan los datos o las operaciones que la API expone.
El rendimiento de una aplicación se puede mejorar almacenando en la caché los datos a los que se accede con frecuencia a un almacenamiento rápido que se encuentra cerca de la aplicación. Las aplicaciones pueden implementar el almacenamiento en caché de lectura con el patrón cache-aside. Este patrón determina si el elemento está actualmente en la memoria caché. Si los datos no se están en la caché, se recuperan del almacén de datos y se agregan a la caché.
Al comunicarse con las API web, las aplicaciones deben ser sensibles a errores transitorios. Los errores transitorios incluyen la pérdida momentánea de conectividad de red a los servicios, la indisponibilidad temporal de un servicio o tiempos de espera que surgen cuando un servicio está ocupado. Estos errores suelen ser de corrección automática y, si la acción se repite después de un intervalo adecuado, es probable que se realice correctamente. Por lo tanto, las aplicaciones deben ajustar todos los intentos de acceder a una API web en el código que implementa un mecanismo de control de errores transitorios.