-
Notifications
You must be signed in to change notification settings - Fork 1
Storage pt BR
🌐 Esta página em: English · Português
Uma assinatura sobre o armazenamento nativo de cada plataforma. Um app escreve o mesmo C# em todo lugar, e o valor aterrissa onde aquela plataforma já guarda esse tipo de coisa — então o backup dela, a migração dela e a desinstalação dela se comportam como o usuário espera, sem o framework inventar ou empacotar nada.
Desde 0.2.0-preview.10
Existem duas interfaces, e qual delas você toma é uma decisão, não um parâmetro.
IAppStorage |
ISecretStore |
|
|---|---|---|
| Web | localStorage |
nenhum, resolve nulo |
| macOS / iOS | NSUserDefaults |
Keychain |
| Android | SharedPreferences |
AES/GCM respaldado por KeyStore |
As duas são tomadas por construtor, como toda outra capacidade:
public sealed class SettingsShell(IAppStorage storage) : StatefulComponent
{
private void Remember(string language) => storage.Set("language", language);
}Todos os alvos. No nativo o container do .NET resolve; no browser o construtor transpilado resolve pelo nome da interface; durante o SSR resolve para um store que não guarda nada e diz isso: leituras respondem
null, escritas não vão a lugar nenhum, porque o armazenamento que isso representa vive na máquina do visitante. Assim uma página lê o valor guardado no primeiro render do cliente, e o markup renderizado no servidor mostra a mesma coisa que uma primeira visita mostra. Veja Capabilities para o quadro inteiro.
Leia no
OnMount, não no construtor: o reconciliador constrói instâncias novas a cada passada e mantém a retida, então um construtor que lê o armazenamento lê de novo para uma instância que é jogada fora. (Componentes write-once)
Colocar um token no localStorage é o erro de segurança mais cometido no web, e uma API onde a
segurança é um argumento secure: true é uma API onde a segurança está a um argumento esquecido de
distância. Aqui a escolha não pode ser feita por omissão: um segredo precisa de um serviço diferente,
e pedir por ele é algo que alguém fez de propósito.
O browser não tem cofre, então no web o ISecretStore resolve para null, do mesmo jeito que o
framework reporta toda capacidade que um host não tem, em vez de fingir com um store que qualquer
script na origem consegue ler. Um app que estende a mão para ele no web precisa responder à pergunta
que estava evitando: manter o segredo no servidor e entregar ao browser uma sessão que ele só pode
gastar, ou aceitar que aquilo que guardava nunca foi realmente um segredo.
No nativo é o cofre real da plataforma. Apple: um item kSecClassGenericPassword por chave sob o
bundle identifier do app, com AfterFirstUnlockThisDeviceOnly para que um refresh em background
consiga ler enquanto um aparelho não desbloqueado desde o boot não consiga, e nunca sincronizado com
o iCloud. Android: uma chave AES respaldada por hardware no AndroidKeyStore (material de chave
ilegível até para este processo) com ciphertext AES/GCM num arquivo de preferências. É o que o
EncryptedSharedPreferences do AndroidX faz, escrito diretamente porque a plataforma entrega cada
peça e o framework não pega dependência para algo que o SO já oferece.
Todo store aqui é um mapa de strings por baixo. Uma superfície tipada seriam três serializadores a manter idênticos, e a primeira discordância entre eles é um valor que escreve numa plataforma e não pode ser lido em outra. Serialize no seu app, onde o formato é seu.
Não existe realização no servidor. Durante o SSR o serviço resolve para null e as leituras não
respondem nada.
Isso importa mais do que parece. Uma página que ramifica a árvore com base em estado guardado renderiza uma coisa no servidor e outra no browser, e o reconciliador vai fielmente reconciliar a diferença na frente do leitor. Leia o armazenamento num handler de evento ou depois do mount, nunca enquanto constrói.
É também por isso que armazenamento sozinho não consegue lembrar um tema sem piscar: o servidor pinta
primeiro e o localStorage não é algo que ele possa ver. Esse problema específico quer um cookie,
porque o requisito não é "lembrar" e sim "contar ao servidor" — e o framework já cuida disso, para
que um app não precise. Veja ServerIntegration.
- O
localStorageé a API do DOM mais propensa a lançar em vez de falhar em silêncio. O modo privado do Safari já lançou na escrita, um browser na cota lança, e lê-lo lança quando a origem está com armazenamento bloqueado. Uma preferência que não conseguiu salvar não pode derrubar a página: uma escrita que não pode acontecer simplesmente não acontece, e uma leitura que não pode acontecer respondenull. - Um item do Keychain não sobrevive a todo restore, e uma chave do KeyStore é invalidada por uma nova tela de bloqueio. Os dois tornam permanentemente ilegível todo valor sob eles.
Então trate uma leitura null como "pergunte de novo" (entre novamente, caia no padrão) e nunca
como um erro a reportar. É a mesma resposta que uma chave nunca escrita dá, e quem chama já sabe
lidar com essa.
Toda capacidade é registrada com TryAdd, então registrar o seu vence:
builder.Services.AddSingleton<IAppStorage, MyOwnStorage>();Essa é a válvula de escape para um store com durabilidade diferente, um arquivo criptografado ou um dublê de teste.
🌐 English · Português
🏁 Comece aqui
📱 Write-once
- Componentes write-once
- Superfície declarativa
- Motor Photon
- Design System
- Capacidades
- Armazenamento
- Formulários
- Editor de código
- Markdown
- Mermaid
- Renderização de Email
🏗️ Arquitetura
⚙️ Compilação
- Compilador
- Avaliação em tempo de compilação
- Recursos C# suportados
- Resolução de tipos externos
- Fluxo de build
- Diagnósticos
⚡ Runtime
🔌 Servidor
🎨 Ecossistema
🚀 Desenvolvimento