Client-Side cache (Browser)
O presente documente serve para expor como a framework trata do armazenamento de informação no lado do cliente (browser).
Overview
Para manipular da melhor forma as potencialidades de armazenamento de informação no browser, foram criados um conjunto de serviços que oferecem uma API que permite efetuar operações set/get/delete a esses dados. Este conjuntos de serviços foram implementados segundo o padrão Façade de forma a esconder a complexidade do sistema de armazenamento de informação.
Independentemente do tipo de cache, os dados armazenados irão ser associados por subscrição e serão comuns em todas as empresas associadas a essa subscrição. Isto significa que subscrições diferentes irão ter dados diferentes, mesmo que não tenha sido feito um refresh à página, fecho da tab, janela ou fecho do browser.
Tipos de cache
Existem três tipos de cache, representando cada uma delas um serviço na aplicação, que oferece uma API que permite fazer operações CRUD aos objetos existentes na cache. Segue-se uma explicação das principais características de cada um dos tipos de cache:
- LocalCache: Todos os dados armazenados não tem uma data de expiração. Não serão eliminados a menos que os dados sejam limpos explicitamente pelo utilizador do browser. Estes dados estão armazenados no
localStoragedo browser. - SessionCache: Os dados armazenados apenas têm a duração da sessão de página existente. Isto significa que se a tab do browser ou o browser é fechado, todos os dados serão apagados. Estes dados estão armazenados no
sessionStoragedo browser. - MemoryCache: Os dados são armazenados apenas em memória. Sempre que a memoria do browser/tab é limpa estes dados também o vão ser. A única diference entre o
SessionCachee oMemoryCacheé que sempre que é feito um reload à página, os dados são eliminados.
Se analizarmos em termos de tempo de vida dos dados, teremos a seguinte hierarquia, onde o topo da piramide significa uma duração menor em relação ao inferior da piramide:

Arquitetura
Existem ao todo três serviços (LocalCacheService, SessionCacheService e MemoryCacheService) que implementam a class abstrata ClienteCacheService.
Esta classe contem três métodos abstratos:
setCache(key: string, prefix: string, object: ICacheble): void– Permite fazer update a um objeto já existente ou adicionar um novo objeto à cache através de uma key e de um prefixo de key.getCache(key: string, prefix: string): ICacheble | null– Permite obter um object a partir da sua key e prefixo.removeCache(key: string, prefix: string): void– Permite remover um objeto da cache a partir da sua key e prefixo.
Diagrama de classes
Segue-se o diagrama de classes que representa as entidades intervenientes bem como as suas relações:

Para ser possível colocar objetos na cache, estes devem de implementar a interface ICacheble.
O serviço AppContextService permite obter o id da subscrição que está a ser utilizada no momento da instanciação do ClientCacheService.
Diagrama de sequencias
Segue-se o diagrama de sequências, que descreve o caso de obter um objeto da cache, utilizando o serviço SessionCacheService:

Exemplo
Segue-se um extrato de código de um serviço que utiliza a cache para manipular objetos que estão armazenados na sessão do browser, através do serviço SessionCacheService:
export class ViewStateStack implements ICacheble {
/** Stack of view states*/
private stack: Array<ViewState> = new Array<ViewState>();
(…)
}
/**
* Service responsible to persiste a view state
*/
@Injectable()
export class ViewStatePersisteService {
/** Key of the cache identifier */
private key: string = "cache";
/** Prefix of the cache identifier*/
private prefix: string = "view";
/** Cache service that allows to persiste the view state*/
private clientCacheService: ClientCacheService;
/** Gets a view state stack from the cache */
private getViewStateStack(): ViewStateStack {
return ViewStateStack.ConvertAnyToStack(
this.clientCacheService.getCache(this.key, this.prefix)
);
}
/** Sets a view state stack to the cache */
private setViewStack(viewFifoStack: ViewStateStack) {
if(viewFifoStack)
this.clientCacheService.setCache(this.key, this.prefix, viewFifoStack);
}
constructor() {
/** Define the cache service as session cache service */
this.clientCacheService = new SessionCacheService();
}
* Verifies if the view state exists
* @param draftId Id of the draft that the view state is associated with
*/
exists(draftId: string): boolean{
return this.get(draftId, false) ? true : false;
}
}
No serviço ViewStatePersisteService, existe uma propriedade clientCacheService do tipo ClientCacheService.
No construtor do serviço, esta class é instanciada como um new SessionCacheService() e utilizada para fazer sets e gets de uma determinada ViewStateStack existente na cache.
É importante nunca definir uma propriedade do tipo de uma class concreta (SessionCacheService) mas sim de uma class abstrata (ClienteCacheService) para facilitar assim a manutenção do código, visto que favorece a troca do tipo de CacheService a utilizar, apenas sendo necessário trocar o serviço que é instanciado (this.clientCacheService = new SessionCacheService()).
Server-Side cache
A Framework Elevation oferece um serviço que abstrai os detalhes de implementação dos mecanismos de cache server-side, e permite uniformizar a sua gestão.
Este documento descreve como deve ser usado o serviço de gestão de cache.
Exemplo de Implementação
Como configurar a cache
<cachingServiceConfiguration>
<elements>
<add name="default" version="v1" isolationKey="staging">
<caches>
<add name="cache-perprocess" handlerType="Primavera.Core.Caching.InProcess.DictionaryCacheHandler, Primavera.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=33086db60a481256">
<settings>
...
<add key="ShortTermTimeout" value="00:05:00" />
<add key="MediumTermTimeout" value="02:00:00" />
<add key="LongTermTimeout" value="12:00:00" />
...
</settings>
</add>
<add name="cache-perapplication" handlerType="Primavera.Core.Caching.Redis.RedisCacheHandler, Primavera.CoreLib.Caching.Redis, Version=4.0.0.0, Culture=neutral, PublicKeyToken=33086db60a481256">
<settings>
...
<add key="RetryBackoff" value="00:00:00.100" />
<add key="ShortTermTimeout" value="00:05:00" />
<add key="MediumTermTimeout" value="02:00:00" />
<add key="LongTermTimeout" value="12:00:00" />
...
</settings>
</add>
</caches>
</add>
</elements>
</cachingServiceConfiguration>
Como obter uma instância do serviço
private ICacheManagementService cacheService = null;
private ICacheManagementService CacheService
{
get
{
if (this.cacheService == null)
{
this.cacheService = ApplicationService.Resolve<ICacheManagementService>();
}
return this.cacheService;
}
}
Como gerar uma chave para items comuns a todas as subscrições
string key = this.CacheService.GenerateCacheKey(false, "MyItemKeyPart1", "MyItemKeyPart2");
formula:
exemplo: "Jamin_v1_staging_MyItemKeyPart1_MyItemKeyPart2
Como gerar uma chave para items da subscrição atual
string key = this.CacheService.GenerateCacheKey(true, "MyItemKeyPart1", "MyItemKeyPart2");
formula:
exemplo: "Jamin_v1_staging_100001_100001-0002_MyItemKeyPart1_MyItemKeyPart2
Como ler um item da cache
string myItemValue = string.Empty;
if (this.CacheService.TryGetValueFromCache(key, out roleData))
{
// Found in cache
...
}
else
{
// Not Found in cache
...
}
Como guardar um item em cache, apenas no primeiro nível (perprocess)
this.CacheService.AddValueToCache<string>("MyItemKey", "MyItemValue", true, false, CacheValueDuration.Medium);
Como guardar um item em cache, nos primeiro e segundo níveis (perprocess e perapplication)
this.CacheService.AddValueToCache<string>("MyItemKey", "MyItemValue", true, true, CacheValueDuration.Medium);
@Author: Ricardo Rocha (ricardo.rocha@primaverabss.com)`