Skip to content

Armadilhas da Store #4: .NET Trimming removeu os bindings do WinUI 3

2026-05-31

Tags: Windows · Microsoft Store · Armadilhas da Store


Esse é um problema que encontrei bem no início. Recentemente, enquanto escrevia esta série de armadilhas, acabei encontrando um antigo e-mail de rejeição — espero que este registro possa servir de referência para desenvolvedores que estão começando com o fluxo de publicação de aplicativos WinUI 3 / .NET.

O que aconteceu

Meu aplicativo WinUI 3 foi enviado para certificação da Microsoft Store. O relatório de certificação voltou com:

Status: Attention needed

10.1.2.10 Functionality

Unusable Feature: "Download to local cache", "Open File" - The product fails to download copied items to local cache and "Open File" button in the product is not usable

Espere — eu testei localmente e tanto "Baixar para cache local" quanto "Abrir arquivo" funcionavam perfeitamente. Por que não funcionariam na máquina de teste da Microsoft?

Investigação

A diferença mais suspeita era: localmente eu usava build Debug, enquanto a versão enviada à Store era build Release. Verificando o arquivo .csproj, descobri uma diferença crucial entre as configurações Debug e Release:

xml
<!-- Debug -->
<PublishTrimmed>False</PublishTrimmed>

<!-- Release -->
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>

A build Release tinha o .NET Trimming ativado.

O que é .NET Trimming

O .NET Trimming é um recurso de otimização do SDK do .NET. Ao publicar um aplicativo, o trimmer realiza uma análise estática para identificar assemblies, tipos e métodos que nunca são diretamente referenciados no código, removendo-os para reduzir o tamanho do aplicativo.

O problema é: o trimmer só enxerga referências estáticas. Se o seu código invoca um tipo via reflexão em tempo de execução, e não há nenhuma referência estática para ele em tempo de compilação, o trimmer considera que o tipo "não é usado" e o remove.

Por que o WinUI 3 é especialmente vulnerável

O WinUI 3 e sua camada de interoperabilidade WinRT subjacente dependem fortemente de reflexão e recursos dinâmicos. Os {Binding} tradicionais, conversores de valor e a reflexão de metadados de interoperabilidade WinRT produzem chamadas em tempo de execução que a análise estática do trimmer não consegue rastrear. Quando o trimmer remove os modelos de dados, comandos, conversores e outros tipos necessários para o binding, tratando-os como "não utilizados", os bindings não encontram seus alvos em tempo de execução — botões param de funcionar, texto para de ser atualizado. Sem erros, sem crashes, as coisas simplesmente param de funcionar silenciosamente.

Solução

A abordagem mais direta: desativar o trimming no .csproj:

diff
- <PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
+ <PublishTrimmed>False</PublishTrimmed>

Reempacotei e reenviei; a certificação passou.

Se você realmente precisa do trimming para reduzir o tamanho do pacote, também é possível torná-lo compatível das seguintes formas:

  • Adicionar os atributos [DynamicDependency] ou [DynamicallyAccessedMembers] nos tipos necessários, informando ao trimmer para preservá-los
  • Configurar <TrimmerRootAssembly> no .csproj para preservar um assembly inteiro

Mas para a maioria dos aplicativos WinUI 3, desativar o trimming diretamente é a opção mais simples.

Resumo

  • O .NET Trimming remove código que ele considera "não utilizado", mas não consegue identificar chamadas via reflexão
  • O data binding do WinUI 3 depende de reflexão, sendo facilmente removido por engano
  • Se um aplicativo WinUI 3 falhar na certificação da Store com "funcionalidade inutilizável" mas funciona localmente, a primeira coisa a verificar é o trimming
  • Builds Debug não aplicam trimming por padrão, mas builds Release podem ativá-lo — sempre teste builds Release/Publish antes de enviar à Store
  • Em breve vamos publicar um artigo com dicas de teste antes de enviar à Store — fiquem ligados

Este artigo pertence à série Armadilhas da Store.