Toegang tot externe gegevens
Tip
Deze inhoud is een fragment uit het eBook, Enterprise Application Patterns Using .NET MAUI, beschikbaar op .NET Docs of als een gratis downloadbare PDF die offline kan worden gelezen.
Veel moderne weboplossingen maken gebruik van webservices, gehost door webservers, om functionaliteit te bieden voor externe clienttoepassingen. De bewerkingen die een webservice beschikbaar maakt, vormen een web-API.
Client-apps moeten de web-API kunnen gebruiken zonder te weten hoe de gegevens of bewerkingen die de API beschikbaar maakt, worden geïmplementeerd. Hiervoor moet de API voldoen aan algemene standaarden waarmee een client-app en webservice kunnen ermee akkoord gaan welke gegevensindelingen moeten worden gebruikt, en de structuur van de gegevens die worden uitgewisseld tussen client-apps en de webservice.
Inleiding tot Representational State Transfer
Representational State Transfer (REST) is een architectuurstijl voor het bouwen van gedistribueerde systemen op basis van hypermedia. Een belangrijk voordeel van het REST-model is dat het is gebaseerd op open standaarden en de implementatie van het model of de client-apps die toegang hebben tot een specifieke implementatie, niet bindt. Daarom kan een REST-webservice worden geïmplementeerd met behulp van Microsoft ASP.NET Core en client-apps kunnen worden ontwikkeld met behulp van elke taal en toolset waarmee HTTP-aanvragen kunnen worden gegenereerd en HTTP-antwoorden kunnen worden geparseerd.
Het REST-model maakt gebruik van een navigatieschema om objecten en services via een netwerk weer te geven, ook wel resources genoemd. Systemen die REST implementeren, gebruiken doorgaans het HTTP-protocol om aanvragen te verzenden voor toegang tot deze resources. In dergelijke systemen verzendt een client-app een aanvraag in de vorm van een URI die een resource identificeert en een HTTP-methode (zoals GET, POST, PUT of DELETE) die aangeeft dat de bewerking moet worden uitgevoerd op die resource. De hoofdtekst van de HTTP-aanvraag bevat alle gegevens die nodig zijn om de bewerking uit te voeren.
Notitie
REST definieert een staatloos aanvraagmodel. Daarom moeten HTTP-aanvragen onafhankelijk zijn en kunnen zich in elke volgorde voordoen.
Het antwoord van een REST-aanvraag maakt gebruik van standaard HTTP-statuscodes. Een aanvraag die geldige gegevens retourneert, moet bijvoorbeeld de HTTP-antwoordcode 200 (OK
) bevatten, terwijl een aanvraag die een opgegeven resource niet kan vinden of verwijderen, een antwoord moet retourneren dat de HTTP-statuscode 404 (Not Found
) bevat.
Een RESTful-web-API maakt een set verbonden resources beschikbaar en biedt de belangrijkste bewerkingen waarmee een app deze resources kan bewerken en er eenvoudig tussen kan navigeren. Daarom zijn de URI's die een typische RESTful-web-API vormen gericht op de gegevens die worden weergegeven en gebruiken de faciliteiten van HTTP om op deze gegevens te werken.
De gegevens die zijn opgenomen door een client-app in een HTTP-aanvraag en de bijbehorende antwoordberichten van de webserver, kunnen worden weergegeven in verschillende indelingen, ook wel mediatypen genoemd. Wanneer een client-app een aanvraag verzendt die gegevens retourneert in de hoofdtekst van een bericht, kan deze de mediatypen opgeven die kunnen worden verwerkt in de header Accepteren van de aanvraag. Als de webserver dit mediatype ondersteunt, kan deze reageren met een antwoord met de header Content-Type waarmee de indeling van de gegevens in de hoofdtekst van het bericht wordt opgegeven. Het is vervolgens de verantwoordelijkheid van de client-app om het antwoordbericht te parseren en de resultaten in de berichttekst op de juiste manier te interpreteren.
Zie API-ontwerp en API-implementatie op Microsoft Docs voor meer informatie over REST.
RESTful-API's gebruiken
De eShop-app voor meerdere platforms maakt gebruik van het MVVM-patroon (Model-View-ViewModel) en de modelelementen van het patroon vertegenwoordigen de domeinentiteiten die in de app worden gebruikt. De controller- en opslagplaatsklassen in de eShop-referentietoepassing accepteren en retourneren veel van deze modelobjecten. Daarom worden ze gebruikt als DTU's (Data Transfer Objects) die alle gegevens bevatten die worden doorgegeven tussen de app en de in containers geplaatste microservices. Het belangrijkste voordeel van het gebruik van DTU's om gegevens door te geven aan en te ontvangen van een webservice is dat door meer gegevens in één externe oproep te verzenden, de app het aantal externe aanroepen kan verminderen dat moet worden gedaan.
Webaanvragen indienen
De eShop-app voor meerdere platforms maakt gebruik van de HttpClient
klasse voor het indienen van aanvragen via HTTP, waarbij JSON wordt gebruikt als mediatype. Deze klasse biedt functionaliteit voor het asynchroon verzenden van HTTP-aanvragen en het ontvangen van HTTP-antwoorden van een geïdentificeerde URI-resource. De klasse HttpResponseMessage vertegenwoordigt een HTTP-antwoordbericht dat is ontvangen van een REST API nadat een HTTP-aanvraag is gedaan. Het bevat informatie over het antwoord, inclusief de statuscode, headers en eventuele hoofdteksten. De HttpContent-klasse vertegenwoordigt de HTTP-hoofdtekst en inhoudsheaders, zoals Content-Type en Content-Encoding. De inhoud kan worden gelezen met behulp van een van de ReadAs
methoden, zoals ReadAsStringAsync
en ReadAsByteArrayAsync
, afhankelijk van de indeling van de gegevens.
Een GET-aanvraag indienen
De CatalogService
klasse wordt gebruikt voor het beheren van het proces voor het ophalen van gegevens uit de microservice van de catalogus. In de RegisterViewModels
methode in de MauiProgram
klasse wordt de CatalogService
klasse geregistreerd als een typetoewijzing voor het ICatalogService
type met de afhankelijkheidsinjectiecontainer. Wanneer vervolgens een exemplaar van de CatalogViewModel
klasse wordt gemaakt, accepteert de constructor een ICatalogService type
, die door de afhankelijkheidsinjectiecontainer wordt omgezet, waarmee een exemplaar van de CatalogService
klasse wordt geretourneerd. Zie Afhankelijkheidsinjectie voor meer informatie over afhankelijkheidsinjectie.
In de onderstaande afbeelding ziet u de interactie van klassen die catalogusgegevens uit de catalogusmicroservice lezen voor weergave door CatalogView.
Wanneer de CatalogView
methode wordt genavigeerd, wordt de OnInitialize
methode in de klasse CatalogViewModel aangeroepen. Met deze methode worden catalogusgegevens opgehaald uit de microservice van de catalogus, zoals wordt gedemonstreerd in het volgende codevoorbeeld:
public override async Task InitializeAsync()
{
Products = await _productsService.GetCatalogAsync();
}
Met deze methode wordt de GetCatalogAsync
methode aangeroepen van het CatalogService
exemplaar dat is geïnjecteerd in de CatalogViewModel
container voor afhankelijkheidsinjectie. In het volgende codevoorbeeld ziet u de GetCatalogAsync
methode:
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;
}
Met deze methode wordt de URI gebouwd waarmee de resource wordt geïdentificeerd waarnaar de aanvraag wordt verzonden en wordt de RequestProvider
klasse gebruikt om de GET HTTP-methode voor de resource aan te roepen, voordat de resultaten naar de CatalogViewModel
resource worden geretourneerd. De RequestProvider
klasse bevat functionaliteit waarmee een aanvraag wordt ingediend in de vorm van een URI die een resource identificeert, een HTTP-methode die aangeeft dat de bewerking moet worden uitgevoerd op die resource en een hoofdtekst met eventuele gegevens die nodig zijn om de bewerking uit te voeren. Zie Afhankelijkheidsinjectie voor informatie over hoe de RequestProvider
klasse wordt geïnjecteerd in de CatalogService
klasse.
In het volgende codevoorbeeld ziet u de GetAsync
methode in de RequestProvider
klasse:
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;
}
Met deze methode wordt de GetOrCreateHttpClient
methode aangeroepen, die een exemplaar van de HttpClient
klasse retourneert met de juiste headerset. Vervolgens wordt een asynchrone GET
aanvraag verzonden naar de resource die is geïdentificeerd door de URI, waarbij het antwoord wordt opgeslagen in het HttpResponseMessage
exemplaar. De HandleResponse
methode wordt vervolgens aangeroepen, waardoor een uitzondering wordt gegenereerd als het antwoord geen HTTP-statuscode met succes bevat. Vervolgens wordt het antwoord gelezen als een tekenreeks, geconverteerd van JSON naar een CatalogRoot
object en geretourneerd naar de CatalogService
.
De GetOrCreateHttpClient
methode wordt weergegeven in het volgende codevoorbeeld:
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;
}
Deze methode maakt gebruik van een nieuw exemplaar of haalt een exemplaar in de cache van de HttpClient
klasse op en stelt de header Accepteren in van alle aanvragen die door het HttpClient
exemplaar application/json
zijn ingediend. Hiermee wordt aangegeven dat de inhoud van een antwoord moet worden opgemaakt met behulp van JSON. Als vervolgens een toegangstoken als argument aan de GetOrCreateHttpClient
methode is doorgegeven, wordt het toegevoegd aan de Authorization
header van aanvragen die door het HttpClient
exemplaar zijn gedaan, voorafgegaan door de tekenreeks Bearer
. Zie Autorisatie voor meer informatie over autorisatie.
Tip
Het wordt ten zeerste aanbevolen om exemplaren van de exemplaren van de cache op te cachen en opnieuw te gebruiken voor betere prestaties van toepassingen HttpClient
. Het maken van een nieuwe HttpClient
bewerking kan leiden tot een probleem met socketuitputting. Zie HttpClient Instancing in het Microsoft Developer Center voor meer informatie.
Wanneer de GetAsync
methode in de RequestProvider
klasse aanroept HttpClient.GetAsync
, wordt de Items
methode in de CatalogController
klasse in het Catalog.API
project aangeroepen, die wordt weergegeven in het volgende codevoorbeeld:
[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);
}
Met deze methode worden de catalogusgegevens opgehaald uit de SQL-database met behulp van EntityFramework en geretourneerd als een antwoordbericht met een geslaagde HTTP-statuscode en een verzameling met JSON-geformatteerde CatalogItem
exemplaren.
Een POST-aanvraag indienen
De BasketService
klasse wordt gebruikt voor het beheren van het proces voor het ophalen en bijwerken van gegevens met de microservice voor manden. In de RegisterAppServices
methode in de MauiProgram
klasse wordt de BasketService
klasse geregistreerd als een typetoewijzing voor het IBasketService
type met de afhankelijkheidsinjectiecontainer. Wanneer een exemplaar van de BasketViewModel
klasse wordt gemaakt, accepteert de constructor vervolgens een IBasketService
type, dat door de afhankelijkheidsinjectiecontainer wordt omgezet, waardoor een exemplaar van de BasketService
klasse wordt geretourneerd. Zie Afhankelijkheidsinjectie voor meer informatie over afhankelijkheidsinjectie.
In de onderstaande afbeelding ziet u de interactie van klassen die de mandgegevens verzenden die door de BasketView worden weergegeven, naar de microservice voor manden.
Wanneer een item wordt toegevoegd aan het winkelwagentje, wordt de ReCalculateTotalAsync
methode in de BasketViewModel
klasse aangeroepen. Met deze methode wordt de totale waarde van items in het mandje bijgewerkt en worden de mandgegevens verzonden naar de microservice voor manden, zoals wordt weergegeven in het volgende codevoorbeeld:
private async Task ReCalculateTotalAsync()
{
// Omitted for brevity...
await _basketService.UpdateBasketAsync(
new CustomerBasket
{
BuyerId = userInfo.UserId,
Items = BasketItems.ToList()
},
authToken);
}
Met deze methode wordt de UpdateBasketAsync
methode aangeroepen van het BasketService
exemplaar dat is geïnjecteerd in de BasketViewModel
container voor afhankelijkheidsinjectie. De volgende methode toont de UpdateBasketAsync
methode:
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;
}
Met deze methode wordt de URI gebouwd waarmee de resource wordt geïdentificeerd waarnaar de aanvraag wordt verzonden en wordt de klasse gebruikt om de RequestProvider
POST HTTP-methode op de resource aan te roepen, voordat de resultaten naar de BasketViewModel
resource worden geretourneerd. Houd er rekening mee dat een toegangstoken, verkregen tijdens IdentityServer
het verificatieproces, is vereist voor het autoriseren van aanvragen voor de microservice voor manden. Zie Autorisatie voor meer informatie over autorisatie.
In het volgende codevoorbeeld ziet u een van de PostAsync
methoden in de RequestProvider
klasse:
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;
}
Met deze methode wordt de GetOrCreateHttpClient
methode aangeroepen, die een exemplaar van de HttpClient
klasse retourneert met de juiste headerset. Vervolgens wordt een asynchrone POST-aanvraag verzonden naar de resource die is geïdentificeerd door de URI, met de geserialiseerde mandgegevens die worden verzonden in JSON-indeling en het antwoord dat wordt opgeslagen in het HttpResponseMessage
exemplaar. De HandleResponse
methode wordt vervolgens aangeroepen, waardoor een uitzondering wordt gegenereerd als het antwoord geen HTTP-statuscode met succes bevat. Vervolgens wordt het antwoord gelezen als een tekenreeks, geconverteerd van JSON naar een CustomerBasket
object en geretourneerd naar de BasketService. Zie Een GET-aanvraag indienen voor meer informatie over de GetOrCreateHttpClient
methode.
Wanneer de PostAsync
methode in de RequestProvider
klasse aanroept HttpClient.PostAsync
, wordt de Post
methode in de BasketController
klasse in het Basket.API
project aangeroepen, die wordt weergegeven in het volgende codevoorbeeld:
[HttpPost]
public async Task<IActionResult> Post([FromBody] CustomerBasket value)
{
var basket = await _repository.UpdateBasketAsync(value);
return Ok(basket);
}
Deze methode maakt gebruik van een exemplaar van de RedisBasketRepository
klasse om de mandgegevens te behouden in de Redis-cache en retourneert deze als een antwoordbericht met een geslaagde HTTP-statuscode en een instantie met JSON-indeling CustomerBasket
.
Een DELETE-aanvraag indienen
In de onderstaande afbeelding ziet u de interacties van klassen waarmee mandgegevens uit de microservice voor de CheckoutView
mand worden verwijderd.
Wanneer het betalingsproces wordt aangeroepen, wordt de CheckoutAsync
methode in de CheckoutViewModel
klasse aangeroepen. Met deze methode maakt u een nieuwe bestelling voordat u het winkelwagentje wist, zoals wordt weergegeven in het volgende codevoorbeeld:
private async Task CheckoutAsync()
{
// Omitted for brevity...
await _basketService.ClearBasketAsync(
_shippingAddress.Id.ToString(), authToken);
}
Met deze methode wordt de ClearBasketAsync
methode aangeroepen van het BasketService
exemplaar dat is geïnjecteerd in de CheckoutViewModel
container voor afhankelijkheidsinjectie. De volgende methode toont de ClearBasketAsync
methode:
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);
}
Deze methode bouwt de URI die de resource identificeert waarnaar de aanvraag wordt verzonden en gebruikt de klasse om de RequestProvider
DELETE
HTTP-methode voor de resource aan te roepen. Houd er rekening mee dat een toegangstoken, verkregen tijdens IdentityServer
het verificatieproces, is vereist voor het autoriseren van aanvragen voor de microservice voor manden. Zie Autorisatie voor meer informatie over autorisatie.
In het volgende codevoorbeeld ziet u de DeleteAsync
methode in de RequestProvider
klasse:
public async Task DeleteAsync(string uri, string token = "")
{
HttpClient httpClient = GetOrCreateHttpClient(token);
await httpClient.DeleteAsync(uri);
}
Met deze methode wordt de GetOrCreateHttpClient
methode aangeroepen, die een exemplaar van de HttpClient
klasse retourneert met de juiste headerset. Vervolgens wordt een asynchrone DELETE
aanvraag verzonden naar de resource die is geïdentificeerd door de URI. Zie Een GET-aanvraag indienen voor meer informatie over de GetOrCreateHttpClient
methode.
Wanneer de DeleteAsync
methode in de RequestProvider
klasse aanroept HttpClient.DeleteAsync
, wordt de Delete
methode in de BasketController
klasse in het Basket.API
project aangeroepen, die wordt weergegeven in het volgende codevoorbeeld:
[HttpDelete("{id}")]
public void Delete(string id) =>
_repository.DeleteBasketAsync(id);
Deze methode gebruikt een exemplaar van de RedisBasketRepository
klasse om de mandgegevens uit de Redis-cache te verwijderen.
Gegevens opslaan in cache
De prestaties van een app kunnen worden verbeterd door veelgebruikte gegevens in de cache op te slaan in de cache voor snelle opslag die zich dicht bij de app bevindt. Als de snelle opslag zich dichter bij de app bevindt dan de oorspronkelijke bron, kan caching de reactietijden aanzienlijk verbeteren bij het ophalen van gegevens.
De meest voorkomende vorm van caching is het lezen van caching, waarbij een app gegevens ophaalt door te verwijzen naar de cache. Als de gegevens zich niet in de cache bevinden, worden ze opgehaald uit het gegevensarchief en aan de cache toegevoegd. Apps kunnen lezen in cache opslaan met het cache-aside-patroon implementeren. Dit patroon bepaalt of het item zich momenteel in de cache bevindt. Als het item zich niet in de cache bevindt, wordt het gelezen uit het gegevensarchief en toegevoegd aan de cache. Zie het patroon Cache-Aside op Microsoft Docs voor meer informatie.
Tip
Cachegegevens die regelmatig worden gelezen en die zelden worden gewijzigd.
Deze gegevens kunnen op aanvraag worden toegevoegd aan de cache wanneer deze voor het eerst worden opgehaald door een app. Dit betekent dat de app de gegevens slechts eenmaal uit het gegevensarchief moet ophalen en dat er aan de volgende toegang kan worden voldaan met behulp van de cache.
Gedistribueerde toepassingen, zoals de eShop-referentietoepassing, moeten een of beide van de volgende caches bieden:
- Een gedeelde cache, die toegankelijk is voor meerdere processen of machines.
- Een privécache, waar gegevens lokaal worden bewaard op het apparaat waarop de app wordt uitgevoerd.
De eShop-app voor meerdere platforms maakt gebruik van een privécache, waarbij gegevens lokaal worden bewaard op het apparaat waarop een exemplaar van de app wordt uitgevoerd.
Tip
U kunt de cache beschouwen als een tijdelijk gegevensarchief dat op elk gewenst moment kan verdwijnen.
Zorg ervoor dat gegevens worden bewaard in het oorspronkelijke gegevensarchief en de cache. De kans op verlies van gegevens wordt vervolgens geminimaliseerd als de cache niet meer beschikbaar is.
Verlooptijd van gegevens beheren
Het is onpraktisch om te verwachten dat gegevens in de cache altijd consistent zijn met de oorspronkelijke gegevens. Gegevens in het oorspronkelijke gegevensarchief kunnen veranderen nadat deze in de cache zijn opgeslagen, waardoor de gegevens in de cache verlopen. Daarom moeten apps een strategie implementeren die ervoor zorgt dat de gegevens in de cache zo actueel mogelijk zijn, maar ook situaties kunnen detecteren en afhandelen die zich voordoen wanneer de gegevens in de cache verlopen zijn. Met de meeste cachemechanismen kan de cache worden geconfigureerd om gegevens te laten verlopen, waardoor de periode wordt beperkt waarvoor gegevens mogelijk verouderd zijn.
Tip
Stel een standaardverlooptijd in bij het configureren van een cache.
Veel caches implementeren verlooptijd, waardoor gegevens ongeldig worden en uit de cache worden verwijderd als deze gedurende een opgegeven periode niet worden geopend. Zorg er echter voor dat u de verloopperiode kiest. Als het te kort is, verlopen gegevens te snel en worden de voordelen van caching verminderd. Als deze te lang is gemaakt, lopen de gegevens risico's verouderd. Daarom moet de verlooptijd overeenkomen met het patroon van toegang voor apps die gebruikmaken van de gegevens.
Wanneer gegevens in de cache verlopen, moeten deze worden verwijderd uit de cache en moet de app de gegevens ophalen uit het oorspronkelijke gegevensarchief en deze weer in de cache plaatsen.
Het is ook mogelijk dat een cache vol raakt als gegevens te lang mogen blijven. Daarom zijn aanvragen om nieuwe items toe te voegen aan de cache mogelijk vereist om bepaalde items in een proces te verwijderen dat bekend staat als verwijdering. Cachingservices maken doorgaans gebruik van gegevens op minst recent gebruikte basis. Er zijn echter andere verwijderingsbeleidsregels, waaronder meest recent gebruikte en first-in-first-out. Zie Richtlijnen voor caching in Microsoft Docs voor meer informatie.
Afbeeldingen opslaan in cache
De eShop-app voor meerdere platforms verbruikt externe productafbeeldingen die profiteren van het opslaan in de cache. Deze afbeeldingen worden weergegeven door het besturingselement Afbeelding. Het besturingselement voor .NET-installatiekopieën MAUI ondersteunt caching van gedownloade installatiekopieën waarvoor caching standaard is ingeschakeld en slaat de installatiekopieën gedurende 24 uur lokaal op. Bovendien kan de verlooptijd worden geconfigureerd met de eigenschap CacheValidity. Zie Downloaded Image Caching in het Microsoft Developer Center voor meer informatie.
Toenemende tolerantie
Alle apps die communiceren met externe services en resources, moeten gevoelig zijn voor tijdelijke fouten. Tijdelijke fouten omvatten het tijdelijke verlies van netwerkconnectiviteit met services, de tijdelijke onbeschikbaarheid van een service of time-outs die optreden wanneer een service bezet is. Deze fouten zijn vaak zelf corrigerend en als de actie wordt herhaald na een geschikte vertraging, slaagt dit waarschijnlijk.
Tijdelijke fouten kunnen een enorme invloed hebben op de waargenomen kwaliteit van een app, zelfs als deze onder alle voorzienbare omstandigheden grondig is getest. Om ervoor te zorgen dat een app die communiceert met externe services betrouwbaar werkt, moet deze het volgende kunnen doen:
- Detecteer fouten wanneer ze optreden en bepaal of de fouten waarschijnlijk tijdelijk zijn.
- Voer de bewerking opnieuw uit als wordt bepaald dat de fout waarschijnlijk tijdelijk is en houd het aantal keren bij dat de bewerking opnieuw is geprobeerd.
- Gebruik een geschikte strategie voor opnieuw proberen, waarmee het aantal nieuwe pogingen, de vertraging tussen elke poging en de acties die moeten worden uitgevoerd na een mislukte poging wordt opgegeven.
Deze tijdelijke foutafhandeling kan worden bereikt door alle pogingen om toegang te krijgen tot een externe service in code die het patroon voor opnieuw proberen implementeert.
Patroon voor opnieuw proberen
Als een app een fout detecteert wanneer een aanvraag naar een externe service wordt verzonden, kan deze de fout op een van de volgende manieren afhandelen:
- Voer de bewerking opnieuw uit. De app kan de mislukte aanvraag onmiddellijk opnieuw proberen.
- Voer de bewerking na een vertraging opnieuw uit. De app moet een geschikte hoeveelheid tijd wachten voordat de aanvraag opnieuw wordt geprobeerd.
- De bewerking wordt geannuleerd. De toepassing moet de bewerking annuleren en een uitzondering rapporteren.
De strategie voor opnieuw proberen moet worden afgestemd op de bedrijfsvereisten van de app. Het is bijvoorbeeld belangrijk om het aantal nieuwe pogingen en het interval voor opnieuw proberen te optimaliseren voor de bewerking die wordt geprobeerd. Als de bewerking deel uitmaakt van een gebruikersinteractie, moet het interval voor opnieuw proberen kort zijn en zijn er slechts enkele nieuwe pogingen geprobeerd om te voorkomen dat gebruikers wachten op een reactie. Als de bewerking deel uitmaakt van een langlopende werkstroom, waarbij het annuleren of opnieuw opstarten van de werkstroom duur of tijdrovend is, is het handig om langer te wachten tussen pogingen en om meer keren opnieuw te proberen.
Notitie
Een agressieve strategie voor opnieuw proberen met minimale vertraging tussen pogingen en een groot aantal nieuwe pogingen kan een externe service die dicht bij of bij capaciteit wordt uitgevoerd, verminderen. Bovendien kan een dergelijke strategie voor opnieuw proberen ook van invloed zijn op de reactiesnelheid van de app als deze voortdurend een mislukte bewerking probeert uit te voeren.
Als een aanvraag na een aantal nieuwe pogingen nog steeds mislukt, is het beter voor de app om verdere aanvragen naar dezelfde resource te voorkomen en een fout te melden. Na een ingestelde periode kan de app vervolgens een of meer aanvragen naar de resource indienen om te zien of ze succesvol zijn. Zie circuitonderbrekerpatroon voor meer informatie.
Tip
Implementeer nooit een mechanisme waarbij eindeloos nieuwe pogingen worden uitgevoerd. Geef in plaats daarvan de voorkeur aan een exponentiële uitstel.
Gebruik een eindig aantal nieuwe pogingen of implementeer het circuitonderbrekerpatroon om een service te laten herstellen.
De eShop-referentietoepassing implementeert het patroon voor opnieuw proberen.
Zie het patroon Opnieuw proberen in Microsoft Docs voor meer informatie over het patroon Voor opnieuw proberen .
Circuitonderbrekerpatroon
In sommige situaties kunnen er fouten optreden vanwege verwachte gebeurtenissen die langer duren voordat ze zijn opgelost. Deze fouten kunnen variëren van een gedeeltelijk verlies van connectiviteit tot de volledige fout van een service. In deze situaties is het zinloos voor een app om een bewerking die waarschijnlijk niet lukt opnieuw uit te voeren. In plaats daarvan moet worden geaccepteerd dat de bewerking is mislukt en deze fout dienovereenkomstig afhandelt.
Het circuitonderbrekerpatroon kan voorkomen dat een app herhaaldelijk probeert een bewerking uit te voeren die waarschijnlijk mislukt, terwijl de app ook kan detecteren of de fout is opgelost.
Notitie
Het doel van het circuitonderbrekerpatroon is anders dan het patroon voor opnieuw proberen. Met het patroon voor opnieuw proberen kan een app een bewerking opnieuw proberen in de verwachting dat deze slaagt. Het circuitonderbrekerpatroon voorkomt dat een app een bewerking uitvoert die waarschijnlijk mislukt.
Een circuitonderbreker fungeert als een proxy voor bewerkingen die kunnen mislukken. De proxy moet het aantal recente fouten controleren dat is opgetreden en deze informatie gebruiken om te bepalen of de bewerking moet worden voortgezet of om onmiddellijk een uitzondering te retourneren.
De eShop-app voor meerdere platforms implementeert momenteel niet het circuitonderbrekerpatroon. De eShop doet het echter wel.
Tip
Combineer de patronen voor opnieuw proberen en circuitonderbrekers.
Een app kan de patronen voor opnieuw proberen en circuitonderbrekers combineren met behulp van het patroon voor opnieuw proberen om een bewerking aan te roepen via een circuitonderbreker. De pogingslogica moet echter gevoelig zijn voor eventuele uitzonderingen die door de circuitonderbreker worden geretourneerd en moet nieuwe pogingen afbreken als de circuitonderbreker aangeeft dat een fout niet tijdelijk is.
Zie het circuitonderbrekerpatroon op Microsoft Docs voor meer informatie over het circuitonderbrekerpatroon .
Samenvatting
Veel moderne weboplossingen maken gebruik van webservices, gehost door webservers, om functionaliteit te bieden voor externe clienttoepassingen. De bewerkingen die een webservice beschikbaar maakt, vormen een web-API en client-apps moeten de web-API kunnen gebruiken zonder te weten hoe de gegevens of bewerkingen die de API beschikbaar maakt, worden geïmplementeerd.
De prestaties van een app kunnen worden verbeterd door veelgebruikte gegevens in de cache op te slaan in de cache voor snelle opslag die zich dicht bij de app bevindt. Apps kunnen lezen in cache opslaan met het cache-aside-patroon implementeren. Dit patroon bepaalt of het item zich momenteel in de cache bevindt. Als het item zich niet in de cache bevindt, wordt het gelezen uit het gegevensarchief en toegevoegd aan de cache.
Wanneer u communiceert met web-API's, moeten apps gevoelig zijn voor tijdelijke fouten. Tijdelijke fouten omvatten het tijdelijke verlies van netwerkconnectiviteit met services, de tijdelijke onbeschikbaarheid van een service of time-outs die optreden wanneer een service bezet is. Deze fouten zijn vaak zelf corrigerend en als de actie na een geschikte vertraging wordt herhaald, is de kans groot dat deze slaagt. Daarom moeten apps alle pogingen verpakken om toegang te krijgen tot een web-API in code waarmee een mechanisme voor tijdelijke foutafhandeling wordt geïmplementeerd.