eQuantic.UIeQuantic.UI
Docs
Playground
GitHub
START HERE
Getting Started
WRITE-ONCE
Write-Once Components
Declarative Surface
Photon Engine
Design System
Capabilities
Storage
Forms
Code Editor
Markdown
Mermaid
Email Rendering
ARCHITECTURE
Architecture Overview
Package Architecture
Components
Styling
Localization
Analytics & GTM
COMPILATION
Compiler
Compile-Time Evaluation
Supported C# Features
External Type Resolution
Build Flow
Diagnostics
RUNTIME
Runtime (TypeScript)
Performance
SERVER
Server Integration
Assets
BunPackage
Security
ECOSYSTEM
Image
Charts
Icons
Lottie
DEVELOPMENT
Visual Editor
Debug
Roadmap
PT-BR
Analytics-pt-BR
Architecture-pt-BR
Assets-pt-BR
BuildFlow-pt-BR
BunPackage-pt-BR
Capabilities-pt-BR
Charts-pt-BR
CodeEditor-pt-BR
Compiler-pt-BR
CompileTimeEvaluation-pt-BR
Components-pt-BR
Debug-pt-BR
DeclarativeSurface-pt-BR
DesignSystem-pt-BR
Diagnostics-pt-BR
EmailRealizer-pt-BR
ExternalTypeResolution-pt-BR
Forms-pt-BR
GettingStarted-pt-BR
Home-pt-BR
Icons-pt-BR
Image-pt-BR
Localization-pt-BR
Lottie-pt-BR
Markdown-pt-BR
Mermaid-pt-BR
PackageArchitecture-pt-BR
Performance-pt-BR
Photon-pt-BR
Roadmap-pt-BR
Runtime-pt-BR
Security-pt-BR
ServerIntegration-pt-BR
Storage-pt-BR
Styling-pt-BR
SupportedFeatures-pt-BR
VisualEditor-pt-BR
WriteOnceComponents-pt-BR
ACTIONS & INPUTS
Button
IconButton
TextInput
Select
Checkbox
Switch
RadioGroup
SegmentedControl
Slider
Stepper
SearchField
SURFACES & DISPLAY
Card
Badge
Chip
Avatar
Banner
ProgressBar
EmptyState
Divider
NAVIGATION
Tabs
AppBar
BottomNavigation
Breadcrumb
Pagination
PageIndicator
Menu
Drawer
OVERLAYS
Dialog
BottomSheet
Toast
Popover
Tooltip
LISTS & DATA
List
ListView
Table
Accordion
CodeBlock
TOUCH INTERACTION
PullToRefresh
SwipeableRow
Docspt-BR
Storage
Edit this page
5 min read
🌐 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:
1
2
3
4
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)
Por que segredos são um tipo diferente
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.
Só strings
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.
Armazenamento é uma capacidade do CLIENTE
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.
Falhas respondem, nunca lançam
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 responde null.
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.
Trazendo o seu
Toda capacidade é registrada com TryAdd, então registrar o seu vence:
1
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.