원격 데이터에 액세스

참고 항목

이 전자책은 2017년 봄에 게시되었으며 그 이후로 업데이트되지 않았습니다. 이 책에는 귀중한 기본 많이 있지만 일부 자료는 구식입니다.

많은 최신 웹 기반 솔루션은 웹 서버에서 호스트되는 웹 서비스를 사용하여 원격 클라이언트 애플리케이션의 기능을 제공합니다. 웹 API는 웹 서비스에 표시되는 작업으로 구성됩니다.

클라이언트 앱은 API가 노출하는 데이터 또는 작업이 구현되는 방식을 알지 못하는 상황에서 웹 API를 활용할 수 있어야 합니다. 즉, API는 클라이언트 앱과 웹 서비스가 사용할 데이터 형식 및 클라이언트 앱과 웹 서비스 간에 교환되는 데이터의 구조를 일치시킬 수 있는 공통 표준을 적용해야 합니다.

Representational State Transfer 소개

REST(Representational State Transfer)는 하이퍼미디어 기반 분산 시스템을 구축하기 위한 아키텍처 스타일입니다. REST 모델의 주요 이점은 개방형 표준을 기반으로 하고 있어 해당 모델의 구현 또는 그 모델에 액세스하는 클라이언트 앱의 구현이 어떠한 특정 구현에도 바인딩되지 않는다는 것입니다. 따라서 Microsoft ASP.NET Core MVC를 사용하여 REST 웹 서비스를 구현할 수 있으며, 클라이언트 앱은 HTTP 요청을 생성하고 HTTP 응답을 구문 분석할 수 있는 언어 및 도구 집합을 사용하여 개발할 수 있습니다.

REST 모델은 탐색 체계를 사용하여 네트워크를 통해 개체 및 서비스(리소스라고 함)를 나타냅니다. 일반적으로 REST를 구현하는 시스템은 HTTP 프로토콜을 사용하여 이러한 리소스에 액세스하기 위한 요청을 전송합니다. 이러한 시스템에서 클라이언트 앱은 하나의 리소스를 식별하는 URI와 해당 리소스에서 수행할 작업을 나타내는 HTTP 메서드(예: GET, POST, PUT 또는 DELETE)의 형식으로 요청을 제출합니다. HTTP 요청의 본문은 작업을 수행하는 데 필요한 모든 데이터를 포함하고 있습니다.

참고

REST는 상태 비저장 요청 모델을 정의합니다. 따라서 HTTP 요청은 독립적이어야 하며 어떤 순서로든 발생할 수 있습니다.

REST 요청에 대한 응답은 표준 HTTP 상태 코드를 사용합니다. 예를 들어 유효한 데이터를 반환하는 요청에는 HTTP 응답 코드 200(확인)이 포함되어야 하지만 지정된 리소스를 찾거나 삭제하지 못하는 요청은 HTTP 상태 코드 404(찾을 수 없음)를 포함하는 응답을 반환해야 합니다.

RESTful 웹 API는 일련의 연결된 리소스를 표시하며 앱이 해당 리소스를 조작하고 리소스 사이를 쉽게 탐색할 수 있도록 하는 코어 작업을 제공합니다. 따라서 일반적인 RESTful 웹 API를 구성하는 URI는 그것이 표시하는 데이터를 지향하며 HTTP가 이 데이터에 대해 작업하기 위해 제공하는 기능을 사용해야 합니다.

HTTP 요청에서 클라이언트 앱이 포함시킨 데이터 및 웹 서버에서 발신되는 해당 응답 메시지를 미디어 형식이라고 하는 다양한 형식으로 제공할 수 있습니다. 클라이언트 앱이 메시지 본문의 데이터를 반환하는 요청을 보내면 요청 헤더에서 처리할 수 있는 미디어 형식을 Accept 지정할 수 있습니다. 웹 서버에서 이 미디어 형식을 지원하는 경우 메시지 본문에 있는 데이터의 형식을 지정하는 헤더가 포함된 Content-Type 응답으로 회신할 수 있습니다. 응답 메시지를 분석하고 메시지 본문의 결과를 적절히 해석하는 것은 클라이언트 앱에서 해야 합니다.

REST에 대한 자세한 내용은 API 디자인API 구현을 참조하세요.

RESTful API 사용

eShopOnContainers 모바일 앱은 MVVM(Model-View-ViewModel) 패턴을 사용하고 패턴의 모델 요소는 앱에 사용되는 do기본 엔터티를 나타냅니다. eShopOnContainers 참조 애플리케이션의 컨트롤러 및 리포지토리 클래스는 이러한 많은 모델 개체를 수락하고 반환합니다. 따라서 모바일 앱과 컨테이너화된 마이크로 서비스 간에 전달되는 모든 데이터를 보유하는 DDO(데이터 전송 개체)로 사용됩니다. DTO를 사용하여 웹 서비스에 데이터를 전달하고 웹 서비스에서 데이터를 받을 때의 주요 이점은 단일 원격 호출에서 더 많은 데이터를 전송하면 앱에서 수행해야 하는 원격 호출 수를 줄일 수 있다는 것입니다.

웹 요청 수행

eShopOnContainers 모바일 앱은 클래스를 HttpClient 사용하여 HTTP를 통해 요청을 만들고 JSON은 미디어 유형으로 사용됩니다. 이 클래스는 HTTP 요청을 비동기적으로 보내고 URI 식별 리소스에서 HTTP 응답을 수신하는 기능을 제공합니다. 이 클래스는 HttpResponseMessage HTTP 요청이 이루어진 후 REST API에서 받은 HTTP 응답 메시지를 나타냅니다. 상태 코드, 헤더 및 모든 본문을 포함 하 여 응답에 대 한 정보를 포함 합니다. 합니다 HttpContent 클래스를 나타내는 HTTP 본문 및 콘텐츠 헤더와 같은 Content-TypeContent-Encoding입니다. 콘텐츠는 데이터 형식에 따라 ReadAsStringAsyncReadAsByteArrayAsync와 같은 ReadAs 메서드를 사용하여 읽을 수 있습니다.

GET 요청 만들기

CatalogService 클래스는 카탈로그 마이크로 서비스에서 데이터 검색 프로세스를 관리하는 데 사용됩니다. 클래스 CatalogServiceRegisterDependencies 메서드에서 ViewModelLocator 클래스는 Autofac 종속성 주입 컨테이너를 ICatalogService 사용하여 형식에 대한 형식 매핑으로 등록됩니다. 그런 다음 클래스의 인스턴스가 CatalogViewModel 만들어지면 해당 생성자는 Autofac이 확인하는 형식을 수락 ICatalogService 하고 클래스의 CatalogService 인스턴스를 반환합니다. 종속성 주입에 대한 자세한 내용은 종속성 주입 소개를 참조하세요.

그림 10-1은 카탈로그 마이크로 서비스에서 카탈로그 데이터를 읽는 클래스의 상호 작용을 보여 줍니다 CatalogView.

Retrieving data from the catalog microservice

그림 10-1: 카탈로그 마이크로 서비스에서 데이터 검색

탐색할 CatalogView 때 클래스의 OnInitialize 메서드가 CatalogViewModel 호출됩니다. 이 메서드는 다음 코드 예제에 설명된 대로 카탈로그 마이크로 서비스에서 카탈로그 데이터를 검색합니다.

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

이 메서드는 GetCatalogAsync Autofac에 의해 삽입된 인스턴스의 CatalogService 메서드를 CatalogViewModel 호출합니다. 다음 코드 예제는 GetCatalogAsync 메서드를 보여줍니다.

public async Task<ObservableCollection<CatalogItem>> GetCatalogAsync()  
{  
    UriBuilder builder = new UriBuilder(GlobalSetting.Instance.CatalogEndpoint);  
    builder.Path = "api/v1/catalog/items";  
    string uri = builder.ToString();  

    CatalogRoot catalog = await _requestProvider.GetAsync<CatalogRoot>(uri);  
    ...  
    return catalog?.Data.ToObservableCollection();            
}

이 메서드는 요청이 전송될 리소스를 식별하는 URI를 빌드하고 RequestProvider 클래스를 사용하여 리소스에 대한 GET HTTP 메서드를 호출한 후 그 결과를 CatalogViewModel로 반환합니다. RequestProvider 클래스에는 리소스를 식별하는 URI 형식으로 요청을 제출하는 기능, 해당 리소스에서 수행할 작업을 나타내는 HTTP 메서드, 작업을 수행하는 데 필요한 데이터가 포함된 본문이 각각 포함됩니다. 클래스가 RequestProvider 삽입되는 CatalogService class방법에 대한 자세한 내용은 종속성 주입 소개를 참조하세요.

다음 코드 예제에서는 RequestProvider 클래스의 GetAsync 메서드를 보여줍니다.

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

    await HandleResponse(response);  
    string serialized = await response.Content.ReadAsStringAsync();  

    TResult result = await Task.Run(() =>   
        JsonConvert.DeserializeObject<TResult>(serialized, _serializerSettings));  

    return result;  
}

이 메서드는 CreateHttpClient 메서드를 호출하여 적절한 헤더가 설정된 HttpClient 클래스의 인스턴스를 반환합니다. 그런 다음, 응답이 인스턴스에 저장 HttpResponseMessage 되는 URI로 식별된 리소스에 비동기 GET 요청을 제출합니다. 그런 다음, HandleResponse 메서드가 호출되며 응답에 성공 HTTP 상태 코드가 포함되지 않은 경우 예외가 발생합니다. 그런 다음, 응답은 문자열로 읽혀지고 JSON에서 CatalogRoot 개체로 변환되며 CatalogService로 반환됩니다.

CreateHttpClient 메서드는 다음 코드 예제에 나와 있습니다.

private HttpClient CreateHttpClient(string token = "")  
{  
    var httpClient = new HttpClient();  
    httpClient.DefaultRequestHeaders.Accept.Add(  
        new MediaTypeWithQualityHeaderValue("application/json"));  

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

이 메서드는 클래스의 HttpClient 새 인스턴스를 만들고 인스턴스에서 수행한 HttpClient 모든 요청의 헤더를 application/jsonJSON을 사용하여 형식이 지정될 것으로 예상한다는 것을 나타내는 헤더를 설정합니다Accept. 그런 다음, 액세스 토큰이 CreateHttpClient 메서드에 인수로 전달된 경우 HttpClient 인스턴스에서 수행한 요청의 Authorization 헤더에 문자열 Bearer의 접두사로 추가됩니다. 권한 부여에 관한 자세한 내용은 권한 부여를 참조하세요.

클래스의 메서드가 GetAsyncRequestProvider 호출 HttpClient.GetAsyncItems 되면 Catalog.API 프로젝트의 클래스에 있는 메서드 CatalogController 가 호출되며 다음 코드 예제에 나와 있습니다.

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

이 메서드는 EntityFramework를 사용하여 SQL 데이터베이스에서 카탈로그 데이터를 검색하고 성공 HTTP 상태 코드 및 JSON 형식 CatalogItem 인스턴스 컬렉션을 포함하는 응답 메시지로 반환합니다.

POST 요청 만들기

BasketService 클래스는 basket 마이크로 서비스를 사용하여 데이터 검색 및 업데이트 프로세스를 관리하는 데 사용됩니다. 클래스 BasketServiceRegisterDependencies 메서드에서 ViewModelLocator 클래스는 Autofac 종속성 주입 컨테이너를 IBasketService 사용하여 형식에 대한 형식 매핑으로 등록됩니다. 그런 다음 클래스의 인스턴스가 BasketViewModel 만들어지면 해당 생성자는 Autofac이 확인하는 형식을 수락 IBasketService 하고 클래스의 BasketService 인스턴스를 반환합니다. 종속성 주입에 대한 자세한 내용은 종속성 주입 소개를 참조하세요.

그림 10-2는 장바구니 마이크로 서비스에 표시된 BasketView장바구니 데이터를 보내는 클래스의 상호 작용을 보여 줍니다.

Sending data to the basket microservice

그림 10-2: 장바구니 마이크로 서비스로 데이터 보내기

하나의 항목이 장바구니에 추가되면 BasketViewModel 클래스의 ReCalculateTotalAsync 메서드가 호출됩니다. 이 메서드는 장바구니에 있는 항목의 총계를 업데이트하고 다음 코드 예제에 설명된 대로 basket 데이터를 basket 마이크로 서비스로 보냅니다.

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

이 메서드는 UpdateBasketAsync Autofac에 의해 삽입된 인스턴스의 BasketService 메서드를 BasketViewModel 호출합니다. 다음 메서드에서는 UpdateBasketAsync 메서드를 보여줍니다.

public async Task<CustomerBasket> UpdateBasketAsync(CustomerBasket customerBasket, string token)  
{  
    UriBuilder builder = new UriBuilder(GlobalSetting.Instance.BasketEndpoint);  
    string uri = builder.ToString();  
    var result = await _requestProvider.PostAsync(uri, customerBasket, token);  
    return result;  
}

이 메서드는 요청이 전송될 리소스를 식별하는 URI를 빌드하고 RequestProvider 클래스를 사용하여 리소스에 대한 POST HTTP 메서드를 호출한 후 그 결과를 BasketViewModel로 반환합니다. 인증 프로세스 중에 IdentityServer에서 가져온 액세스 토큰은 장바구니 마이크로 서비스에 대한 요청에 권한을 부여해야 합니다. 권한 부여에 관한 자세한 내용은 권한 부여를 참조하세요.

다음 코드 예제에서는 RequestProvider 클래스의 PostAsync 메서드 중 하나를 보여 줍니다.

public async Task<TResult> PostAsync<TResult>(  
    string uri, TResult data, string token = "", string header = "")  
{  
    HttpClient httpClient = CreateHttpClient(token);  
    ...  
    var content = new StringContent(JsonConvert.SerializeObject(data));  
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");  
    HttpResponseMessage response = await httpClient.PostAsync(uri, content);  

    await HandleResponse(response);  
    string serialized = await response.Content.ReadAsStringAsync();  

    TResult result = await Task.Run(() =>  
        JsonConvert.DeserializeObject<TResult>(serialized, _serializerSettings));  

    return result;  
}

이 메서드는 CreateHttpClient 메서드를 호출하여 적절한 헤더가 설정된 HttpClient 클래스의 인스턴스를 반환합니다. 그런 다음, 직렬화된 basket 데이터가 JSON 형식으로 전송되고 응답이 HttpResponseMessage 인스턴스에 저장되는 상태에서 URI로 식별된 리소스에 비동기 POST 요청을 제출합니다. 그런 다음, HandleResponse 메서드가 호출되며 응답에 성공 HTTP 상태 코드가 포함되지 않은 경우 예외가 발생합니다. 그런 다음, 응답이 문자열로 읽혀지고 JSON에서 개체로 CustomerBasket 변환되고 BasketService. 메서드에 대한 CreateHttpClient 자세한 내용은 GET 요청 만들기를 참조하세요.

클래스의 메서드가 PostAsyncRequestProvider 호출 HttpClient.PostAsyncPost 되면 Basket.API 프로젝트의 클래스에 있는 메서드 BasketController 가 호출됩니다. 이 메서드는 다음 코드 예제에 나와 있습니다.

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

이 메서드는 RedisBasketRepository 클래스의 인스턴스를 사용하여 basket 데이터를 Redis 캐시에 유지하며, 이 데이터를 성공 HTTP 상태 코드 및 JSON 형식 CustomerBasket 인스턴스를 포함하는 응답 메시지로 반환합니다.

DELETE 요청 만들기

그림 10-3은 장바구니 마이크로 서비스에서 장바구니 데이터를 삭제하는 클래스의 상호 작용을 CheckoutView보여 줍니다.

Deleteing data from the basket microservice

그림 10-3: 장바구니 마이크로 서비스에서 데이터 삭제

체크 아웃 프로세스가 호출되면 CheckoutViewModel 클래스의 CheckoutAsync 메서드가 호출됩니다. 이 메서드는 다음 코드 예제와 같이 장바구니를 지우기 전에 새 주문을 만듭니다.

private async Task CheckoutAsync()  
{  
    ...  
    await _basketService.ClearBasketAsync(_shippingAddress.Id.ToString(), authToken);  
    ...  
}

이 메서드는 ClearBasketAsync Autofac에 의해 삽입된 인스턴스의 BasketService 메서드를 CheckoutViewModel 호출합니다. 다음 메서드에서는 ClearBasketAsync 메서드를 보여줍니다.

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

이 메서드는 요청이 전송될 리소스를 식별하는 URI를 빌드하고 클래스를 RequestProvider 사용하여 리소스에서 DELETE HTTP 메서드를 호출합니다. 인증 프로세스 중에 IdentityServer에서 가져온 액세스 토큰은 장바구니 마이크로 서비스에 대한 요청에 권한을 부여해야 합니다. 권한 부여에 관한 자세한 내용은 권한 부여를 참조하세요.

다음 코드 예제에서는 RequestProvider 클래스의 DeleteAsync 메서드를 보여줍니다.

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

이 메서드는 CreateHttpClient 메서드를 호출하여 적절한 헤더가 설정된 HttpClient 클래스의 인스턴스를 반환합니다. 그런 다음 URI로 식별된 리소스에 비동기 DELETE 요청을 제출합니다. 메서드에 대한 CreateHttpClient 자세한 내용은 GET 요청 만들기를 참조하세요.

클래스의 메서드가 DeleteAsyncRequestProvider 호출 HttpClient.DeleteAsyncDelete 되면 Basket.API 프로젝트의 클래스에 있는 메서드 BasketController 가 호출됩니다. 이 메서드는 다음 코드 예제에 나와 있습니다.

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

이 메서드는 RedisBasketRepository 클래스의 인스턴스를 사용하여 Redis 캐시에서 장바구니 데이터를 삭제합니다.

데이터 캐싱

자주 액세스하는 데이터를 앱 가까이에 있는 빠른 스토리지에 캐싱하여 앱의 성능을 향상시킬 수 있습니다. 빠른 스토리지가 원래 원본보다 앱에 더 가까이 있는 경우 캐싱은 데이터를 검색할 때 응답 시간을 크게 향상시킬 수 있습니다.

캐싱의 가장 일반적인 형태는 앱이 캐시를 참조하여 데이터를 검색하는 read-through 캐싱입니다. 캐시에 데이터가 없으면 데이터 저장소에서 데이터가 검색된 후 캐시에 추가됩니다. 앱은 캐시 배제 패턴을 사용하여 read-through 캐싱을 구현할 수 있습니다. 이 패턴은 해당 항목이 현재 캐시에 있는지 여부를 결정합니다. 캐시에 해당 항목이 없으면 데이터 저장소의 데이터를 읽은 후 캐시에 추가합니다. 자세한 내용은 Cache-Aside 패턴을 참조하세요.

자주 읽고 자주 변경되지 않는 데이터를 캐시합니다. 이 데이터는 앱에서 맨 처음 검색되었을 때 필요에 따라 캐시에 추가할 수 있습니다. 즉, 앱이 데이터 저장소에서 한 번만 데이터를 가져와야 하며 이후 액세스는 캐시를 사용하여 충족할 수 있습니다.

eShopOnContainers 참조 애플리케이션과 같은 분산 애플리케이션은 다음 캐시 중 하나 또는 둘 다를 제공해야 합니다.

  • 여러 프로세스 또는 컴퓨터에서 액세스할 수 있는 공유 캐시입니다.
  • 앱을 실행하는 디바이스에서 데이터가 로컬에 보관되는 프라이빗 캐시입니다.

eShopOnContainers 모바일 앱은 프라이빗 캐시를 사용합니다. 여기서 데이터는 앱 인스턴스를 실행하는 디바이스에서 로컬로 유지됩니다. eShopOnContainers 참조 애플리케이션에서 사용하는 캐시에 관한 자세한 내용은 .NET 마이크로 서비스: 컨테이너화된 .NET 애플리케이션에 대한 아키텍처를 참조하세요.

캐시는 언제든지 사라질 수 있는 임시 데이터 저장소로 간주하세요. 데이터가 원래 데이터 저장소와 캐시에서 유지 관리되는지 확인합니다. 캐시를 사용할 수 없게 되면 데이터 손실 가능성이 최소화됩니다.

데이터 만료 관리

캐시된 데이터가 항상 원래 데이터와 일치할 것으로 예상하는 것은 비현실적입니다. 원래 데이터 저장소의 데이터는 캐시된 이후 변경될 수 있으며 이는 캐시된 데이터의 생산성을 떨어뜨리게 됩니다. 따라서 앱은 캐시에 보관된 데이터를 최신 상태로 유지할 수 있도록 지원하는 전략을 구현하는 동시에, 캐시에 보관된 오래된 데이터로 인해 발생하는 상황을 감지하고 처리할 수 있어야 합니다. 대부분의 캐싱 메커니즘을 사용하면 데이터를 만료하도록 캐시를 구성할 수 있으며, 데이터가 만료될 수 있는 기간을 단축할 수 있습니다.

캐시를 구성할 때 기본 만료 시간을 설정합니다. 상당수의 캐시는 규정된 기간 동안 액세스하지 않은 경우 데이터를 무효화하고 캐시에서 삭제하는 만료를 구현합니다. 그러나 만료 기간을 선택할 때는 주의해야 합니다. 기간이 너무 짧으면 데이터가 너무 빨리 만료되며 캐싱의 이점이 줄어듭니다. 기간이 너무 길어지면 데이터 위험이 부실해질 수 있습니다. 따라서 만료 시간은 데이터를 사용하는 앱에 대한 액세스 패턴과 일치해야 합니다.

캐시된 데이터가 만료되면 캐시에서 데이터를 제거해야 하며 앱은 원래 데이터 저장소에서 데이터를 검색하여 캐시에 다시 배치해야 합니다.

데이터를 너무 오랜 기간동안 유지하도록 허용하면 캐시를 채우는 것도 가능합니다. 따라서 제거로 알려진 프로세스에서 일부 항목을 제거하려면 캐시에 새 항목을 추가하라는 요청이 필요할 수 있습니다. 캐싱 서비스는 대체로 가장 최근에 사용한 기준으로 데이터를 제거합니다. 그러나 가장 최근에 사용한 정책 및 선착순을 포함한 다른 제거 정책이 있습니다. 자세한 내용은 캐싱 지침을 참조 하세요.

이미지 캐싱

eShopOnContainers 모바일 앱은 캐시되는 이점을 활용하는 원격 제품 이미지를 사용합니다. 이러한 이미지는 컨트롤 및 CachedImage FFImageLoading 라이브러리에서 제공하는 컨트롤에 의해 Image 표시됩니다.

컨트롤은 Xamarin.FormsImage 다운로드한 이미지의 캐싱을 지원합니다. 캐싱은 기본적으로 사용하도록 설정되며 24시간 동안 이미지를 로컬로 저장합니다. 또한 만료 시간은 속성을 사용하여 CacheValidity 구성할 수 있습니다. 자세한 내용은 다운로드한 이미지 캐싱을 참조 하세요.

FFImageLoading의 CachedImage 컨트롤은 컨트롤을 Xamarin.FormsImage 대체하여 추가 기능을 가능하게 하는 추가 속성을 제공합니다. 이 기능 중에서 컨트롤은 구성 가능한 캐싱을 제공하면서 오류를 지원하고 이미지 자리 표시자를 로드합니다. 다음 코드 예제에서는 eShopOnContainers 모바일 앱에서 ProductTemplate컨트롤을 사용하는 CachedImage 방법을 보여 하며, 컨트롤에서 CatalogView사용하는 ListView 데이터 템플릿은 다음과 같습니다.

<ffimageloading:CachedImage
    Grid.Row="0"
    Source="{Binding PictureUri}"     
    Aspect="AspectFill">
    <ffimageloading:CachedImage.LoadingPlaceholder>
        <OnPlatform x:TypeArguments="ImageSource">
            <On Platform="iOS, Android" Value="default_campaign" />
            <On Platform="UWP" Value="Assets/default_campaign.png" />
        </OnPlatform>
    </ffimageloading:CachedImage.LoadingPlaceholder>
    <ffimageloading:CachedImage.ErrorPlaceholder>
        <OnPlatform x:TypeArguments="ImageSource">
            <On Platform="iOS, Android" Value="noimage" />
            <On Platform="UWP" Value="Assets/noimage.png" />
        </OnPlatform>
    </ffimageloading:CachedImage.ErrorPlaceholder>
</ffimageloading:CachedImage>

컨트롤은 CachedImage 플랫폼별 이미지로 속성 및 ErrorPlaceholder 속성을 설정합니다LoadingPlaceholder. 속성에서 LoadingPlaceholder 지정한 이미지를 검색하는 동안 표시할 이미지를 지정하고 ErrorPlaceholder 속성에서 지정 SourceSource 한 이미지를 검색하려고 할 때 오류가 발생하면 표시할 이미지를 지정합니다.

이름에서 알 수 있듯이 컨트롤은 CachedImage 속성 값으로 지정된 시간 동안 디바이스의 원격 이미지를 캐시합니다 CacheDuration . 이 속성 값이 명시적으로 설정되지 않은 경우 기본값인 30일이 적용됩니다.

복원력 향상

원격 서비스 및 리소스와 통신하는 모든 앱은 일시적인 오류에 민감해야 합니다. 일시적인 오류로는 서비스의 순간적인 네트워크 연결 끊김, 서비스의 일시적인 사용 중단, 서비스가 사용 중일 때 발생하는 시간 제한 등이 있습니다. 이러한 오류는 종종 자동으로 수정되며 적절한 지연 후에 작업이 반복되면 성공할 가능성이 높습니다.

일시적인 오류는 예측 가능한 모든 환경에서 완벽하게 테스트된 경우에도 앱의 인지된 품질에 큰 영향을 미칠 수 있습니다. 원격 서비스와 통신하는 앱이 안정적으로 작동하려면 다음 사항들을 모두 수행할 수 있어야 합니다.

  • 오류가 발생할 때 오류를 감지하고 오류가 일시적일 수 있는지 확인합니다.
  • 오류가 일시적인 것으로 확인되면 작업을 재시도하고 해당 작업의 재시도 횟수를 추적합니다.
  • 재시도 횟수, 각 시도 간 지연 및 시도 실패 후 수행할 작업을 규정하는 적절한 재시도 전략을 활용합니다.

이 일시적인 오류 처리는 재시도 패턴을 구현하는 코드에서 원격 서비스에 액세스하려는 모든 시도를 래핑하여 수행할 수 있습니다.

다시 시도 패턴

앱이 원격 서비스에 요청을 보내려 할 때 오류를 감지할 경우 다음과 같은 방법으로 오류를 처리할 수 있습니다.

  • 작업을 다시 시도합니다. 앱에서 실패한 요청을 즉시 다시 시도할 수 있습니다.
  • 지연 후 작업을 다시 시도합니다. 앱은 요청을 다시 시도하기 전에 적절한 시간 동안 대기해야 합니다.
  • 작업을 취소합니다. 애플리케이션은 작업을 취소하고 예외를 보고해야 합니다.

재시도 전략은 앱의 비즈니스 요구 사항에 맞게 조정해야 합니다. 예를 들어, 시도 중인 작업에 맞게 재시도 횟수 및 재시도 간격을 최적화하는 것이 중요합니다. 작업이 사용자 상호 작용의 일부에 속하는 경우, 재시도 간격은 짧아야 하며 사용자가 응답을 기다리지 않도록 몇 번의 재시도만 해야 합니다. 작업이 장기 실행 워크플로의 일부에 속하며 워크플로를 취소하거나 다시 시작하는 데 비용이 많이 들거나 시간이 많이 소요되는 경우, 시도 간 대기 시간을 더 길게 유지하고 재시도 횟수를 늘리는 것이 적절합니다.

참고

시도간 지연 시간을 최소화한 적극적인 재시도 전략과 많은 재시도 횟수는 수용작업량에 근접하거나 수용작업량으로 실행 중인 원격 서비스의 질을 저하시킬 수 있습니다. 또한 계속해서 실패한 작업을 수행하려는 경우, 이러한 재시도 전략은 앱의 응답성에 영향을 미칠 수도 있습니다.

수많은 재시도 후에도 요청이 계속 실패하는 경우, 앱에서 후속 요청이 동일한 리소스로 가지 않도록 하고 이러한 실패를 보고하는 것이 좋습니다. 그런 다음, 설정된 기간이 지나면 앱이 리소스에 대해 하나 이상의 요청을 수행하여 요청이 성공했는지 확인할 수 있습니다. 자세한 내용은 회로 차단기 패턴을 참조 하세요.

무한 재시도 메커니즘을 구현하지 않습니다. 한정된 수의 재시도를 적용하거나 회로 차단기 패턴을 구현하여 서비스에서 복구할 수 있도록 합니다.

eShopOnContainers 모바일 앱은 현재 RESTful 웹 요청을 할 때 재시도 패턴을 구현하지 않습니다. 그러나 FFImageLoading 라이브러리에서 제공하는 컨트롤 CachedImage은 이미지 로드를 다시 시도하여 일시적인 오류 처리를 지원합니다. 이미지 로드에 실패하면 추가 시도가 이루어집니다. 시도 횟수는 속성에 의해 RetryCount 지정되며 속성에서 지정한 지연 후에 다시 시도됩니다 RetryDelay . 이러한 속성 값이 명시적으로 설정되지 않은 경우 해당 기본값이 적용됩니다. 속성의 RetryCount 경우 3, 속성의 경우 250ms가 RetryDelay 적용됩니다. 컨트롤에 대한 CachedImage 자세한 내용은 이미지 캐싱을 참조 하세요.

eShopOnContainers 참조 애플리케이션은 재시도 패턴을 구현합니다. 재시도 패턴을 클래스와 HttpClient 결합하는 방법에 대한 설명을 비롯한 자세한 내용은 .NET 마이크로 서비스: 컨테이너화된 .NET 애플리케이션에 대한 아키텍처를 참조 하세요.

재시도 패턴에 대한 자세한 내용은 다시 시도 패턴을 참조하세요.

회로 차단기 패턴

경우에 따라서는 수정하는 데 시간이 더 오래 걸리는 예상 이벤트로 인해 오류가 발생할 수 있습니다. 이러한 오류는 부분적 연결 손실에서부터 전체 서비스 오류에 이르기까지 다양하게 나타날 수 있습니다. 이러한 상황에서 성공할 가능성이 없는 작업을 앱이 다시 시도하는 것은 무의미하며, 그 대신 작업이 실패했음을 받아들이고 그에 따라 이 오류를 처리해야 합니다.

회로 차단기 패턴은 오류가 해결되었는지 여부를 앱이 감지하는 동시에 실패할 가능성이 있는 작업을 앱에서 반복적으로 실행하는 것을 방지할 수 있습니다.

참고

회로 차단기 패턴의 목적은 재시도 패턴과는 다릅니다. 재시도 패턴을 사용하면 앱에서 작업이 성공한다는 기대로 작업을 다시 시도할 수 있습니다. 회로 차단기 패턴은 실패할 가능성이 있는 작업을 앱이 수행하지 않도록 합니다.

회로 차단기는 실패할 수 있는 작업에서 프록시 역할을 합니다. 프록시는 발생한 최근 오류 수를 모니터링하거나, 이 정보를 사용하여 작업을 진행하도록 허용할지를 결정하거나 예외를 즉시 반환해야 합니다.

eShopOnContainers 모바일 앱은 현재 회로 차단기 패턴을 구현하지 않습니다. 그러나 eShopOnContainers는 이 패턴을 구현합니다. 자세한 내용은 .NET 마이크로 서비스: 컨테이너화된 .NET 애플리케이션을 위한 아키텍처를 참조하세요.

재시도 및 회로 차단기 패턴을 결합합니다. 앱은 재시도 패턴을 사용하여 회로 차단기를 통해 작업을 호출하여 재시도 및 회로 차단기 패턴을 결합할 수 있습니다. 그러나 재시도 논리는 회로 차단기에서 반환되는 모든 예외에 민감하며, 회로 차단기에서 오류가 일시적임을 나타내는 경우 재시도를 중단합니다.

회로 차단기 패턴에 대한 자세한 내용은 회로 차단기 패턴을 참조하세요.

요약

많은 최신 웹 기반 솔루션은 웹 서버에서 호스트되는 웹 서비스를 사용하여 원격 클라이언트 애플리케이션의 기능을 제공합니다. 웹 서비스가 노출하는 작업은 웹 API를 구성하며, 클라이언트 앱은 API가 노출하는 데이터 또는 작업이 구현되는 방식을 모르는 상태에서 웹 API를 활용할 수 있어야 합니다.

자주 액세스하는 데이터를 앱 가까이에 있는 빠른 스토리지에 캐싱하여 앱의 성능을 향상시킬 수 있습니다. 앱은 캐시 배제 패턴을 사용하여 read-through 캐싱을 구현할 수 있습니다. 이 패턴은 해당 항목이 현재 캐시에 있는지 여부를 결정합니다. 캐시에 해당 항목이 없으면 데이터 저장소의 데이터를 읽은 후 캐시에 추가합니다.

웹 API와 통신할 때 앱은 일시적인 오류에 민감해야 합니다. 일시적인 오류로는 서비스의 순간적인 네트워크 연결 끊김, 서비스의 일시적인 사용 중단, 서비스가 사용 중일 때 발생하는 시간 제한 등이 있습니다. 이러한 오류는 종종 자동으로 수정되며 적절한 지연 후에 작업이 반복되면 성공할 가능성이 높습니다. 따라서 앱은 일시적인 오류 처리 메커니즘을 구현하는 코드에서 웹 API에 액세스하려는 모든 시도를 래핑해야 합니다.