Uzyskiwanie dostępu do danych zdalnych
Napiwek
Ta zawartość jest fragmentem książki eBook, wzorców aplikacji dla przedsiębiorstw przy użyciu platformy .NET, dostępnej na platformie .NET MAUIDocs lub jako bezpłatnego pliku PDF do pobrania, który można odczytać w trybie offline.
Wiele nowoczesnych rozwiązań internetowych korzysta z usług internetowych hostowanych przez serwery internetowe w celu zapewnienia funkcjonalności zdalnych aplikacji klienckich. Operacje uwidaczniane przez usługę internetową stanowią internetowy interfejs API.
Aplikacje klienckie powinny mieć możliwość korzystania z internetowego interfejsu API bez znajomości sposobu implementacji danych lub operacji udostępnianych przez interfejs API. Wymaga to, aby interfejs API przestrzegał wspólnych standardów, które umożliwiają aplikacji klienckiej i usłudze internetowej uzgodnienie formatów danych do użycia oraz strukturę danych wymienianych między aplikacjami klienckimi a usługą internetową.
Wprowadzenie do reprezentacji transferu stanu
Representational State Transfer (REST) to styl architektury do tworzenia systemów rozproszonych opartych na hipermediach. Główną zaletą modelu REST jest to, że jest on oparty na otwartych standardach i nie wiąże implementacji modelu ani aplikacji klienckich, które uzyskują dostęp do niej do żadnej konkretnej implementacji. W związku z tym można zaimplementować usługę internetową REST przy użyciu platformy Microsoft ASP.NET Core, a aplikacje klienckie mogą być opracowywane przy użyciu dowolnego zestawu narzędzi i języka, które mogą generować żądania HTTP i analizować odpowiedzi HTTP.
Model REST używa schematu nawigacji do reprezentowania obiektów i usług za pośrednictwem sieci, nazywanych zasobami. Systemy implementujące architekturę REST zwykle używają protokołu HTTP do przesyłania żądań w celu uzyskania dostępu do tych zasobów. W takich systemach aplikacja kliencka przesyła żądanie w postaci identyfikatora URI, który identyfikuje zasób, oraz metodę HTTP (np. GET, POST, PUT lub DELETE), która wskazuje operację do wykonania w tym zasobie. Treść żądania HTTP zawiera wszystkie dane wymagane do wykonania operacji.
Uwaga
Interfejs REST definiuje model żądania bezstanowego. W związku z tym żądania HTTP muszą być niezależne i mogą występować w dowolnej kolejności.
Odpowiedź z żądania REST korzysta ze standardowych kodów stanu HTTP. Na przykład żądanie zwracające prawidłowe dane powinno zawierać kod odpowiedzi HTTP 200 (OK
), podczas gdy żądanie, które nie może odnaleźć lub usunąć określonego zasobu, powinno zwrócić odpowiedź zawierającą kod stanu HTTP 404 (Not Found
).
Internetowy interfejs API RESTful uwidacznia zestaw połączonych zasobów i udostępnia podstawowe operacje, które umożliwiają aplikacji manipulowanie tymi zasobami i łatwe nawigowanie między nimi. Z tego powodu identyfikatory URI, które stanowią typowy internetowy interfejs API RESTful, są zorientowane na dane, które uwidaczniają, i używają obiektów udostępnianych przez protokół HTTP do działania na tych danych.
Dane zawarte przez aplikację kliencką w żądaniu HTTP i odpowiednie komunikaty odpowiedzi z serwera internetowego mogą być prezentowane w różnych formatach, znanych jako typy multimediów. Gdy aplikacja kliencka wysyła żądanie zwracające dane w treści komunikatu, może określić typy multimediów, które mogą obsłużyć w nagłówku Accept żądania. Jeśli serwer internetowy obsługuje ten typ nośnika, może odpowiedzieć z odpowiedzią zawierającą nagłówek Content-Type, który określa format danych w treści wiadomości. Następnie aplikacja kliencka odpowiada za analizowanie komunikatu odpowiedzi i odpowiednie interpretowanie wyników w treści komunikatu.
Aby uzyskać więcej informacji na temat architektury REST, zobacz Projektowanie interfejsu API i implementacja interfejsu API w witrynie Microsoft Docs.
Korzystanie z interfejsów API RESTful
Aplikacja wieloplatformowa eShop używa wzorca Model-View-ViewModel (MVVM), a elementy modelu wzorca reprezentują jednostki domeny używane w aplikacji. Klasy kontrolera i repozytorium w aplikacji referencyjnej eShop akceptują i zwracają wiele z tych obiektów modelu. W związku z tym są one używane jako obiekty transferu danych (DTO), które przechowują wszystkie dane przekazywane między aplikacją a konteneryzowanymi mikrousługami. Główną zaletą używania jednostek DTO do przekazywania danych i odbierania danych z usługi internetowej jest to, że przesyłając więcej danych w jednym wywołaniu zdalnym, aplikacja może zmniejszyć liczbę zdalnych wywołań, które należy wykonać.
Tworzenie żądań internetowych
Aplikacja wieloplatformowa HttpClient
eShop używa klasy do tworzenia żądań za pośrednictwem protokołu HTTP, a kod JSON jest używany jako typ nośnika. Ta klasa zapewnia funkcje asynchronicznego wysyłania żądań HTTP i odbierania odpowiedzi HTTP z zidentyfikowanego zasobu identyfikatora URI. Klasa HttpResponseMessage reprezentuje komunikat odpowiedzi HTTP odebrany z interfejsu API REST po wykonaniu żądania HTTP. Zawiera on informacje o odpowiedzi, w tym kod stanu, nagłówki i dowolną treść. Klasa HttpContent reprezentuje treść HTTP i nagłówki zawartości, takie jak Content-Type i Content-Encoding. Zawartość może być odczytywana przy użyciu dowolnej metody ReadAs
, takiej jak ReadAsStringAsync
i ReadAsByteArrayAsync
, w zależności od formatu danych.
Tworzenie żądania GET
Klasa CatalogService
służy do zarządzania procesem pobierania danych z mikrousługi wykazu. W metodzie RegisterViewModels
MauiProgram
w klasie CatalogService
klasa jest rejestrowana jako mapowanie typu względem ICatalogService
typu z kontenerem iniekcji zależności. Następnie po utworzeniu CatalogViewModel
wystąpienia klasy konstruktor akceptuje klasę ICatalogService type
, która jest rozpoznawana przez kontener wstrzykiwania zależności, zwracając wystąpienie CatalogService
klasy. Aby uzyskać więcej informacji na temat wstrzykiwania zależności, zobacz Wstrzykiwanie zależności.
Na poniższej ilustracji przedstawiono interakcję klas odczytujących dane wykazu z mikrousługi wykazu do wyświetlania przez element CatalogView.
Po przejściu CatalogView
do OnInitialize
metody w klasie CatalogViewModel jest wywoływana. Ta metoda pobiera dane wykazu z mikrousługi wykazu, jak pokazano w poniższym przykładzie kodu:
public override async Task InitializeAsync()
{
Products = await _productsService.GetCatalogAsync();
}
Ta metoda wywołuje metodę GetCatalogAsync
CatalogService
wystąpienia, które zostało wprowadzone do CatalogViewModel
kontenera iniekcji zależności. Poniższy przykład kodu przedstawia metodę 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;
}
Ta metoda tworzy identyfikator URI, który identyfikuje zasób, do którego zostanie wysłane żądanie, i używa RequestProvider
klasy do wywołania metody HTTP GET w zasobie przed zwróceniem wyników do CatalogViewModel
klasy . Klasa RequestProvider
zawiera funkcje, które przesyłają żądanie w postaci identyfikatora URI identyfikującego zasób, metodę HTTP wskazującą operację do wykonania na tym zasobie, oraz treść zawierającą wszelkie dane wymagane do wykonania operacji. Aby uzyskać informacje na temat sposobu RequestProvider
wstrzykiwania klasy do CatalogService
klasy, zobacz Wstrzykiwanie zależności.
Poniższy przykład kodu przedstawia metodę GetAsync
RequestProvider
w klasie:
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;
}
Ta metoda wywołuje metodę GetOrCreateHttpClient
, która zwraca wystąpienie HttpClient
klasy z odpowiednim zestawem nagłówków. Następnie przesyła żądanie asynchroniczne GET
do zasobu zidentyfikowanego przez identyfikator URI z odpowiedzią przechowywaną w wystąpieniu HttpResponseMessage
. HandleResponse
Następnie wywoływana jest metoda, która zgłasza wyjątek, jeśli odpowiedź nie zawiera kodu stanu HTTP powodzenia. Następnie odpowiedź jest odczytywana jako ciąg, konwertowana z formatu JSON na CatalogRoot
obiekt i zwracana do obiektu CatalogService
.
Metoda jest pokazana GetOrCreateHttpClient
w poniższym przykładzie kodu:
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;
}
Ta metoda używa tworzenia nowego wystąpienia lub pobierania buforowanego wystąpienia HttpClient
klasy i ustawia nagłówek Accept wszystkich żądań wysyłanych przez HttpClient
wystąpienie na application/json
wartość , co wskazuje, że oczekuje zawartości dowolnej odpowiedzi sformatowanej przy użyciu formatu JSON. Następnie, jeśli token dostępu został przekazany jako argument do GetOrCreateHttpClient
metody, jest dodawany do Authorization
nagłówka wszystkich żądań wysyłanych przez HttpClient
wystąpienie, poprzedzony ciągiem Bearer
. Aby uzyskać więcej informacji na temat autoryzacji, zobacz Autoryzacja.
Napiwek
Zdecydowanie zaleca się buforowanie i ponowne używanie wystąpień programu w HttpClient
celu uzyskania lepszej wydajności aplikacji. Utworzenie nowego HttpClient
elementu dla każdej operacji może prowadzić do problemu z wyczerpaniem gniazd. Aby uzyskać więcej informacji, zobacz HttpClient Instancing w Centrum deweloperów firmy Microsoft.
GetAsync
Gdy metoda w RequestProvider
klasie wywołuje HttpClient.GetAsync
metodę , Items
wywoływana jest metoda w CatalogController
klasie w Catalog.API
projekcie, która jest wyświetlana w poniższym przykładzie kodu:
[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);
}
Ta metoda pobiera dane wykazu z bazy danych SQL przy użyciu elementu EntityFramework i zwraca je jako komunikat odpowiedzi zawierający kod stanu HTTP powodzenia oraz kolekcję wystąpień sformatowanych CatalogItem
w formacie JSON.
Tworzenie żądania POST
Klasa BasketService
służy do zarządzania procesem pobierania i aktualizowania danych za pomocą mikrousługi koszyka. W metodzie RegisterAppServices
MauiProgram
w klasie BasketService
klasa jest rejestrowana jako mapowanie typu względem IBasketService
typu z kontenerem iniekcji zależności. Następnie po utworzeniu BasketViewModel
wystąpienia klasy konstruktor akceptuje IBasketService
typ, który jest rozpoznawany przez kontener iniekcji zależności, zwracając wystąpienie BasketService
klasy. Aby uzyskać więcej informacji na temat wstrzykiwania zależności, zobacz Wstrzykiwanie zależności.
Na poniższej ilustracji przedstawiono interakcję klas, które wysyłają dane koszyka wyświetlane przez element BasketView do mikrousługi koszyka.
Po dodaniu elementu do koszyka zakupów wywoływana ReCalculateTotalAsync
jest metoda w BasketViewModel
klasie . Ta metoda aktualizuje łączną wartość elementów w koszyku i wysyła dane koszyka do mikrousługi koszyka, jak pokazano w poniższym przykładzie kodu:
private async Task ReCalculateTotalAsync()
{
// Omitted for brevity...
await _basketService.UpdateBasketAsync(
new CustomerBasket
{
BuyerId = userInfo.UserId,
Items = BasketItems.ToList()
},
authToken);
}
Ta metoda wywołuje metodę UpdateBasketAsync
BasketService
wystąpienia, które zostało wprowadzone do BasketViewModel
kontenera iniekcji zależności. Poniższa metoda przedstawia metodę 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;
}
Ta metoda tworzy identyfikator URI, który identyfikuje zasób, do którego zostanie wysłane żądanie, i używa RequestProvider
klasy do wywołania metody HTTP POST w zasobie przed zwróceniem wyników do BasketViewModel
klasy . Należy pamiętać, że token dostępu uzyskany z IdentityServer
procesu uwierzytelniania jest wymagany do autoryzowania żądań do mikrousługi koszyka. Aby uzyskać więcej informacji na temat autoryzacji, zobacz Autoryzacja.
Poniższy przykład kodu przedstawia jedną z PostAsync
metod w RequestProvider
klasie:
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;
}
Ta metoda wywołuje metodę GetOrCreateHttpClient
, która zwraca wystąpienie HttpClient
klasy z odpowiednim zestawem nagłówków. Następnie przesyła asynchroniczne żądanie POST do zasobu zidentyfikowanego przez identyfikator URI z serializowanymi danymi koszyka wysyłanymi w formacie JSON i odpowiedzią przechowywaną w wystąpieniu HttpResponseMessage
. HandleResponse
Następnie wywoływana jest metoda, która zgłasza wyjątek, jeśli odpowiedź nie zawiera kodu stanu HTTP powodzenia. Następnie odpowiedź jest odczytywana jako ciąg, konwertowana z formatu JSON na CustomerBasket
obiekt i zwracana do usługi BasketService. Aby uzyskać więcej informacji na temat GetOrCreateHttpClient
metody, zobacz Tworzenie żądania GET.
PostAsync
Gdy metoda w RequestProvider
klasie wywołuje HttpClient.PostAsync
metodę , Post
wywoływana jest metoda w BasketController
klasie w Basket.API
projekcie, która jest wyświetlana w poniższym przykładzie kodu:
[HttpPost]
public async Task<IActionResult> Post([FromBody] CustomerBasket value)
{
var basket = await _repository.UpdateBasketAsync(value);
return Ok(basket);
}
Ta metoda używa wystąpienia RedisBasketRepository
klasy do utrwalania danych koszyka w pamięci podręcznej Redis Cache i zwraca je jako komunikat odpowiedzi zawierający kod stanu HTTP powodzenia oraz wystąpienie sformatowane CustomerBasket
w formacie JSON.
Tworzenie żądania DELETE
Na poniższej ilustracji przedstawiono interakcje klas, które usuwają dane koszyka z mikrousługi koszyka dla klasy CheckoutView
.
Po wywołaniu procesu wyewidencjonowania wywoływana CheckoutAsync
jest metoda w CheckoutViewModel
klasie . Ta metoda tworzy nowe zamówienie przed wyczyszczeniem koszyka zakupów, jak pokazano w poniższym przykładzie kodu:
private async Task CheckoutAsync()
{
// Omitted for brevity...
await _basketService.ClearBasketAsync(
_shippingAddress.Id.ToString(), authToken);
}
Ta metoda wywołuje metodę ClearBasketAsync
BasketService
wystąpienia, które zostało wprowadzone do CheckoutViewModel
kontenera iniekcji zależności. Poniższa metoda przedstawia metodę 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);
}
Ta metoda tworzy identyfikator URI, który identyfikuje zasób, do którego zostanie wysłane żądanie, i używa RequestProvider
klasy do wywołania DELETE
metody HTTP w zasobie. Należy pamiętać, że token dostępu uzyskany z IdentityServer
procesu uwierzytelniania jest wymagany do autoryzowania żądań do mikrousługi koszyka. Aby uzyskać więcej informacji na temat autoryzacji, zobacz Autoryzacja.
Poniższy przykład kodu przedstawia metodę DeleteAsync
RequestProvider
w klasie:
public async Task DeleteAsync(string uri, string token = "")
{
HttpClient httpClient = GetOrCreateHttpClient(token);
await httpClient.DeleteAsync(uri);
}
Ta metoda wywołuje metodę GetOrCreateHttpClient
, która zwraca wystąpienie HttpClient
klasy z odpowiednim zestawem nagłówków. Następnie przesyła żądanie asynchroniczne DELETE
do zasobu zidentyfikowanego przez identyfikator URI. Aby uzyskać więcej informacji na temat GetOrCreateHttpClient
metody, zobacz Tworzenie żądania GET.
DeleteAsync
Gdy metoda w RequestProvider
klasie wywołuje HttpClient.DeleteAsync
metodę , Delete
wywoływana jest metoda w BasketController
klasie w Basket.API
projekcie, która jest wyświetlana w poniższym przykładzie kodu:
[HttpDelete("{id}")]
public void Delete(string id) =>
_repository.DeleteBasketAsync(id);
Ta metoda używa wystąpienia RedisBasketRepository
klasy do usunięcia danych koszyka z pamięci podręcznej Redis Cache.
Buforowanie danych
Wydajność aplikacji można poprawić przez buforowanie często używanych danych do szybkiego magazynu znajdującego się w pobliżu aplikacji. Jeśli szybki magazyn znajduje się bliżej aplikacji niż oryginalne źródło, buforowanie może znacznie poprawić czas odpowiedzi podczas pobierania danych.
Najczęstszą formą buforowania jest buforowanie odczytu, w którym aplikacja pobiera dane, odwołując się do pamięci podręcznej. Jeśli dane nie znajdują się w pamięci podręcznej, zostaną pobrane z magazynu danych i dodane do pamięci podręcznej. Aplikacje mogą implementować buforowanie odczytu za pomocą wzorca z odkładaniem do pamięci podręcznej. Ten wzorzec określa, czy element znajduje się obecnie w pamięci podręcznej. Jeśli element nie znajduje się w pamięci podręcznej, jest odczytywany z magazynu danych i dodawany do pamięci podręcznej. Aby uzyskać więcej informacji, zobacz Wzorzec odkładania do pamięci podręcznej w witrynie Microsoft Docs.
Napiwek
Buforuj dane, które są często odczytywane i zmieniają się rzadko.
Te dane można dodać do pamięci podręcznej na żądanie przy pierwszym pobraniu przez aplikację. Oznacza to, że aplikacja musi pobrać dane tylko raz z magazynu danych, a kolejny dostęp może zostać spełniony przy użyciu pamięci podręcznej.
Aplikacje rozproszone, takie jak aplikacja referencyjna eShop, powinny zawierać zarówno następujące pamięci podręczne, jak i obie z następujących pamięci podręcznych:
- Udostępniona pamięć podręczna, do której można uzyskać dostęp przez wiele procesów lub maszyn.
- Prywatna pamięć podręczna, w której dane są przechowywane lokalnie na urządzeniu z uruchomioną aplikacją.
Aplikacja wieloplatformowa eShop używa prywatnej pamięci podręcznej, w której dane są przechowywane lokalnie na urządzeniu, na którym uruchomiono wystąpienie aplikacji.
Napiwek
Pamięć podręczna jest uważana za przejściowy magazyn danych, który może zniknąć w dowolnym momencie.
Upewnij się, że dane są przechowywane w oryginalnym magazynie danych, a także w pamięci podręcznej. Szanse na utratę danych są następnie zminimalizowane, jeśli pamięć podręczna stanie się niedostępna.
Zarządzanie wygaśnięciem danych
Niepraktyczne jest oczekiwanie, że buforowane dane będą zawsze zgodne z oryginalnymi danymi. Dane w oryginalnym magazynie danych mogą ulec zmianie po ich buforowanej pamięci podręcznej, co powoduje, że dane z pamięci podręcznej staną się nieaktualne. W związku z tym aplikacje powinny wdrożyć strategię, która pomaga zapewnić, że dane w pamięci podręcznej są tak aktualne, jak to możliwe, ale mogą również wykrywać i obsługiwać sytuacje, które pojawiają się, gdy dane w pamięci podręcznej staną się nieaktualne. Większość mechanizmów buforowania umożliwia skonfigurowanie pamięci podręcznej w celu wygaśnięcia danych, a tym samym skrócenie okresu, w którym dane mogą być nieaktualne.
Napiwek
Ustaw domyślny czas wygaśnięcia podczas konfigurowania pamięci podręcznej.
Wiele pamięci podręcznych implementuje wygaśnięcie, co unieważnia dane i usuwa je z pamięci podręcznej, jeśli nie jest uzyskiwany dostęp przez określony okres. Należy jednak zachować ostrożność podczas wybierania okresu wygaśnięcia. Jeśli będzie zbyt krótki, dane wygasną zbyt szybko, a korzyści z buforowania zostaną zmniejszone. Jeśli jest on zbyt długi, ryzyko związane z danymi staje się nieaktualne. W związku z tym czas wygaśnięcia powinien być zgodny ze wzorcem dostępu dla aplikacji korzystających z danych.
Po wygaśnięciu buforowanych danych należy je usunąć z pamięci podręcznej, a aplikacja musi pobrać dane z oryginalnego magazynu danych i umieścić je z powrotem w pamięci podręcznej.
Istnieje również możliwość, że pamięć podręczna może zostać wypełniona, jeśli dane mogą pozostać zbyt długo. W związku z tym żądania dodania nowych elementów do pamięci podręcznej mogą być wymagane do usunięcia niektórych elementów w procesie znanym jako eksmisji. usługa buforowania zwykle eksmituje dane z najmniej ostatnio używanych danych. Istnieją jednak inne zasady eksmisji, w tym ostatnio używane i pierwszy na pierwszym wyjęcie. Aby uzyskać więcej informacji, zobacz Wskazówki dotyczące buforowania w witrynie Microsoft Docs.
Buforowanie obrazów
Aplikacja wieloplatformowa eShop korzysta ze zdalnych obrazów produktów, które korzystają z buforowania. Te obrazy są wyświetlane przez kontrolkę Obraz. Kontrolka Obraz platformy .NET MAUI obsługuje buforowanie pobranych obrazów, które domyślnie ma włączoną buforowanie i będzie przechowywać obraz lokalnie przez 24 godziny. Ponadto można skonfigurować czas wygaśnięcia za pomocą właściwości CacheValidity. Aby uzyskać więcej informacji, zobacz Pobieranie buforowania obrazów w Centrum deweloperów firmy Microsoft.
Zwiększenie odporności
Wszystkie aplikacje komunikujące się z usługami zdalnymi i zasobami muszą być wrażliwe na błędy przejściowe. Przejściowe błędy obejmują chwilową utratę łączności sieciowej z usługami, tymczasową niedostępność usługi lub przekroczenia limitu czasu, gdy usługa jest zajęta. Te błędy są często samonaprawiające, a jeśli akcja jest powtarzana po odpowiednim opóźnieniu, prawdopodobnie zakończy się powodzeniem.
Błędy przejściowe mogą mieć ogromny wpływ na postrzeganą jakość aplikacji, nawet jeśli została dokładnie przetestowana we wszystkich przewidywalnych okolicznościach. Aby zapewnić niezawodne działanie aplikacji komunikującej się z usługami zdalnymi, musi być w stanie wykonać wszystkie następujące czynności:
- Wykrywaj błędy, gdy wystąpią, i ustal, czy błędy mogą być przejściowe.
- Spróbuj ponownie wykonać operację, jeśli ustali, że błąd może być przejściowy i śledzić liczbę ponownych prób wykonania operacji.
- Użyj odpowiedniej strategii ponawiania, która określa liczbę ponownych prób, opóźnienie między poszczególnymi próbami i akcje do wykonania po nieudanej próbie.
Tę przejściową obsługę błędów można osiągnąć, opakowując wszystkie próby uzyskania dostępu do usługi zdalnej w kodzie, który implementuje wzorzec ponawiania prób.
Wzorzec ponawiania
Jeśli aplikacja wykryje błąd podczas próby wysłania żądania do usługi zdalnej, może obsłużyć błąd w dowolny z następujących sposobów:
- Ponów próbę wykonania operacji. Aplikacja może natychmiast ponowić próbę żądania zakończonego niepowodzeniem.
- Ponów próbę wykonania operacji po opóźnieniu. Aplikacja powinna poczekać odpowiedni czas przed ponowieniu próby żądania.
- Anulowanie operacji. Aplikacja powinna anulować operację i zgłosić wyjątek.
Strategia ponawiania prób powinna być dostosowana do wymagań biznesowych aplikacji. Na przykład ważne jest, aby zoptymalizować liczbę ponownych prób i interwał ponawiania prób do próby wykonania operacji. Jeśli operacja jest częścią interakcji użytkownika, interwał ponawiania prób powinien być krótki i tylko kilka ponownych prób próbowało uniknąć oczekiwania użytkowników na odpowiedź. Jeśli operacja jest częścią długotrwałego przepływu pracy, w którym anulowanie lub ponowne uruchomienie przepływu pracy jest kosztowne lub czasochłonne, należy poczekać dłużej między próbami i ponowić próbę więcej razy.
Uwaga
Agresywna strategia ponawiania z minimalnym opóźnieniem między próbami i dużą liczbą ponownych prób może obniżyć wydajność zdalnej usługi, która jest uruchomiona blisko lub w pojemności. Ponadto taka strategia ponawiania prób może również mieć wpływ na czas odpowiedzi aplikacji, jeśli stale próbuje wykonać operację kończącą się niepowodzeniem.
Jeśli żądanie nadal kończy się niepowodzeniem po wielu ponownych próbach, lepiej jest zapobiec dalszym żądaniom przechodzącym do tego samego zasobu i zgłaszać błąd. Następnie po upływie określonego okresu aplikacja może wysyłać do zasobu co najmniej jedno żądanie, aby sprawdzić, czy zakończyły się powodzeniem. Aby uzyskać więcej informacji, zobacz Wzorzec wyłącznika.
Napiwek
Nigdy nie implementuj mechanizmu nieskończonego ponawiania prób. Zamiast tego preferuj wycofywanie wykładnicze.
Użyj skończonej liczby ponownych prób lub zaimplementuj wzorzec wyłącznika , aby umożliwić usłudze odzyskiwanie.
Aplikacja referencyjna eShop implementuje wzorzec ponawiania prób.
Aby uzyskać więcej informacji na temat wzorca ponawiania, zobacz Wzorzec ponawiania prób w witrynie Microsoft Docs.
Wzorzec wyłącznika
W niektórych sytuacjach błędy mogą wystąpić z powodu przewidywanych zdarzeń, które potrwają dłużej. Te błędy mogą wahać się od częściowej utraty łączności do całkowitej awarii usługi. W takich sytuacjach nie ma sensu, aby aplikacja ponawiała próbę wykonania operacji, która prawdopodobnie nie powiedzie się, i zamiast tego powinna zaakceptować, że operacja zakończyła się niepowodzeniem i odpowiednio obsłuży tę awarię.
Wzorzec wyłącznika może uniemożliwić aplikacji wielokrotne wykonywanie operacji, która prawdopodobnie zakończy się niepowodzeniem, a jednocześnie umożliwić aplikacji wykrywanie, czy błąd został rozwiązany.
Uwaga
Przeznaczenie wzorca wyłącznika różni się od wzorca ponawiania. Wzorzec ponawiania umożliwia aplikacji ponowienie próby wykonania operacji w oczekiwaniu, że zakończy się powodzeniem. Wzorzec wyłącznika uniemożliwia aplikacji wykonywanie operacji, która prawdopodobnie zakończy się niepowodzeniem.
Wyłącznik działa jako serwer proxy dla operacji, które mogą zakończyć się niepowodzeniem. Serwer proxy powinien monitorować liczbę ostatnich awarii i użyć tych informacji, aby zdecydować, czy zezwolić operacji na kontynuowanie, czy natychmiast zwrócić wyjątek.
Aplikacja wieloplatformowa eShop nie implementuje obecnie wzorca wyłącznika. Jednak eShop robi.
Napiwek
Połącz wzorce ponawiania prób i wyłącznika.
Aplikacja może połączyć wzorce ponawiania prób i wyłącznika przy użyciu wzorca ponawiania w celu wywołania operacji za pośrednictwem wyłącznika. Jednak logika ponawiania powinna uwzględniać ewentualne wyjątki zwracane przez wyłącznik i przerwać ponawianie prób, jeśli wyłącznik wskazuje, że błąd nie jest przejściowy.
Aby uzyskać więcej informacji na temat wzorca wyłącznika, zobacz wzorzec wyłącznika w witrynie Microsoft Docs.
Podsumowanie
Wiele nowoczesnych rozwiązań internetowych korzysta z usług internetowych hostowanych przez serwery internetowe w celu zapewnienia funkcjonalności zdalnych aplikacji klienckich. Operacje uwidaczniane przez usługę internetową stanowią internetowy interfejs API, a aplikacje klienckie powinny mieć możliwość korzystania z internetowego interfejsu API bez znajomości sposobu implementacji danych lub operacji udostępnianych przez interfejs API.
Wydajność aplikacji można poprawić przez buforowanie często używanych danych do szybkiego magazynu znajdującego się w pobliżu aplikacji. Aplikacje mogą implementować buforowanie odczytu za pomocą wzorca z odkładaniem do pamięci podręcznej. Ten wzorzec określa, czy element znajduje się obecnie w pamięci podręcznej. Jeśli element nie znajduje się w pamięci podręcznej, jest odczytywany z magazynu danych i dodawany do pamięci podręcznej.
Podczas komunikowania się z internetowymi interfejsami API aplikacje muszą być wrażliwe na błędy przejściowe. Przejściowe błędy obejmują chwilową utratę łączności sieciowej z usługami, tymczasową niedostępność usługi lub przekroczenia limitu czasu, gdy usługa jest zajęta. Te błędy są często samonaprawiające, a jeśli akcja jest powtarzana po odpowiednim opóźnieniu, prawdopodobnie zakończy się powodzeniem. W związku z tym aplikacje powinny opakowywać wszystkie próby uzyskania dostępu do internetowego interfejsu API w kodzie, który implementuje mechanizm obsługi błędów przejściowych.