.NET 11 Preview 3: o que há de novo nas bibliotecas

O .NET 11 Preview 3 continua o ciclo de previews da plataforma e traz melhorias concretas nas bibliotecas da Base Class Library (BCL). As mudanças não são cosméticas, porque atendem demandas reais de quem lida com serialização JSON, compressão de dados, I/O de baixo nível e processamento de texto.

Este artigo detalha cada uma das principais novidades dessa versão, com exemplos de código, impactos práticos e as breaking changes que exigem atenção antes de migrar.

Contexto: onde o .NET 11 se posiciona

O .NET 11 é uma versão de Standard Term Support (STS), com lançamento planejado para novembro de 2026. Assim como as demais versões ímpares, ele alterna com as versões LTS, como o .NET 10.

Vale corrigir um número que circulou bastante: as versões STS agora recebem 24 meses de suporte. A Microsoft estendeu esse prazo a partir do .NET 9, enquanto as versões LTS continuam com no mínimo três anos.

Mesmo sendo STS, o .NET 11 concentra mudanças arquiteturais relevantes, como o Runtime Async e melhorias no JIT. Agora, no .NET 11 Preview 3, a vez é das bibliotecas da BCL.

Se você quer acompanhar a evolução completa, vale ler também as novidades nas bibliotecas base do Preview 1 e o que mudou no runtime, JIT e WebAssembly do Preview 3.

System.Text.Json no .NET 11 Preview 3

A biblioteca System.Text.Json recebeu três novos recursos no .NET 11 Preview 3. Todos ampliam o controle declarativo sobre a serialização.

PascalCase nativo no .NET 11 Preview 3

O primeiro recurso é a política JsonNamingPolicy.PascalCase, que se junta às políticas já existentes de camelCase, snake_case e kebab-case. Também existe o valor equivalente JsonKnownNamingPolicy.PascalCase, usado em atributos.

Com isso, quem precisa serializar objetos em PascalCase não precisa mais criar uma política customizada. Esse cenário é comum na integração com APIs legadas e serviços que adotam essa convenção.

Política de nomes por membro e ignore no nível do tipo

O segundo recurso é o atributo [JsonNamingPolicy], aplicável diretamente em membros individuais e também em tipos. Até então, a política de nomenclatura era configurada globalmente via JsonSerializerOptions, sem como sobrescrevê-la para uma propriedade específica.

O terceiro recurso permite aplicar [JsonIgnore(Condition = ...)] no nível do tipo, e não apenas no nível da propriedade. Assim, você define na própria classe o comportamento padrão de ignorar valores nulos, sem repetir o atributo em cada membro.

O exemplo a seguir ilustra os três recursos combinados:

using System.Text.Json;
using System.Text.Json.Serialization;

// Todos os membros ignoram valores nulos por padrão
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public sealed class EventData
{
    // Este membro usa camelCase, mesmo com PascalCase global
    [JsonNamingPolicy(JsonKnownNamingPolicy.CamelCase)]
    public string EventName { get; set; } = "";

    public string? Notes { get; set; }
}

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.PascalCase
};

Nesse exemplo, as opções usam PascalCase globalmente, mas a propriedade EventName substitui esse comportamento por camelCase. Além disso, como o [JsonIgnore] está na classe, a propriedade Notes some do JSON quando seu valor é nulo.

Ordem de precedência das regras

A documentação do .NET 11 detalha a precedência dos nomes. Primeiro vale o [JsonPropertyName], depois o [JsonNamingPolicy] do membro, em seguida o do tipo, depois a PropertyNamingPolicy das opções e, por fim, o nome original.

No caso do ignore, o [JsonIgnore] do membro vence o do tipo, que por sua vez vence o DefaultIgnoreCondition das opções. No entanto, JsonIgnoreCondition.Always não é válido no nível do tipo.

Nesse caso, a serialização por reflection lança InvalidOperationException. Já o source generator emite o diagnóstico SYSLIB1226 e ignora o atributo do tipo.

Essa granularidade reduz código repetitivo e torna os modelos mais expressivos por si mesmos.

Zstandard migra para System.IO.Compression

A API Zstandard, introduzida no início do ciclo do .NET 11 como um pacote separado, foi movida para o namespace System.IO.Compression no .NET 11 Preview 3. Dessa forma, o ZstandardStream passa a conviver com DeflateStream, GZipStream e BrotliStream.

Segundo a documentação, a superfície da API não mudou, apenas o lugar onde ela mora. Para quem já testava a versão anterior, a ação necessária é remover a referência ao pacote separado do .csproj:

<!-- Remova esta referência do .csproj -->
<PackageReference Include="System.IO.Compression.Zstandard" />

A partir dessa versão, a API está disponível diretamente no SDK, sem dependência adicional. O uso segue o mesmo padrão dos outros streams de compressão:

using System.IO.Compression;

// Comprime um arquivo usando Zstandard
await using FileStream input = File.OpenRead("report.json");
await using FileStream output = File.Create("report.json.zst");
await using var zstd = new ZstandardStream(output, CompressionLevel.Optimal);

await input.CopyToAsync(zstd);

Quem já usa BrotliStream ou GZipStream não precisa aprender nada novo. Basta trocar a classe e escolher o nível de compressão.

Além do ZstandardStream, o namespace traz tipos de mais baixo nível, como o ZstandardEncoder. Eles são úteis quando você trabalha direto com buffers e quer evitar a criação de um stream para cada operação.

Validação de CRC32 em arquivos ZIP

O .NET 11 Preview 3 também adiciona validação de CRC32 ao ler entradas ZIP. Antes dessa mudança, arquivos ZIP corrompidos ou truncados eram aceitos silenciosamente durante a leitura.

Agora, entradas inválidas disparam InvalidDataException, o que facilita a detecção de corrupção em fluxos que dependem de integridade. Por outro lado, essa também é uma breaking change, detalhada mais adiante.

Para quem acompanha a evolução do ZipArchive, vale ler sobre as otimizações no ZipArchive no .NET 10, que prepararam o terreno para essas mudanças.

SafeFileHandle e RandomAccess no .NET 11 Preview 3

O .NET 11 Preview 3 traz um conjunto de melhorias de baixo nível para I/O, com foco especial em pipes e handles do sistema operacional.

A primeira adição é a propriedade SafeFileHandle.Type, que informa o tipo do handle: arquivo, pipe, socket, diretório ou outro objeto do sistema operacional. Isso ajuda quando o mesmo código lida com fontes diferentes e precisa decidir com base no tipo real do handle, sem código específico de plataforma.

A segunda adição é o método estático SafeFileHandle.CreateAnonymousPipe. Ele cria pares de pipes conectados, com comportamento assíncrono configurável para cada extremidade.

using Microsoft.Win32.SafeHandles;

// Cria um pipe anônimo: leitura assíncrona, escrita síncrona
SafeFileHandle.CreateAnonymousPipe(
    out SafeFileHandle readEnd,
    out SafeFileHandle writeEnd,
    asyncReads: true,
    asyncWrites: false);

using (readEnd)
using (writeEnd)
{
    Console.WriteLine(readEnd.Type); // Pipe
}

Os nomes asyncReads e asyncWrites são os das notas do Preview 3. Contudo, a documentação atual do .NET 11 já mostra os parâmetros como asyncRead e asyncWrite, então confira a assinatura do SDK que você estiver usando.

A terceira mudança é que RandomAccess.Read e RandomAccess.Write agora funcionam com handles não posicionáveis, como pipes. Antes, a classe exigia handles com suporte a seek, o que limitava seu uso a arquivos comuns.

No Windows, há ainda uma melhoria importante: o Process passou a usar overlapped I/O para redirecionar stdout e stderr. Com isso, aplicações que iniciam muitos processos filhos, como ferramentas de build e runners de testes, bloqueiam menos o thread pool.

Regex com AnyNewLine no .NET 11 Preview 3

O .NET 11 Preview 3 introduz a flag RegexOptions.AnyNewLine. Ela faz com que as âncoras ^ e $ e o ponto . tratem como terminadores de linha todos os caracteres de nova linha do Unicode.

Até então, sem essa flag, apenas \n era tratado como nova linha. Com RegexOptions.AnyNewLine, os seguintes caracteres também passam a ser reconhecidos:

  • \r\n (CRLF do Windows)
  • \r (Carriage Return isolado)
  • \u0085 (Next Line, NEL)
  • 
 (Line Separator)
  • 
 (Paragraph Separator)

O exemplo a seguir demonstra o uso com texto misto:

using System.Text.RegularExpressions;

string text = "line1\r\nline2\u0085line3
line4";

// Reconhece qualquer terminador de linha do Unicode
var matches = Regex.Matches(
    text,
    @"^line\d$",
    RegexOptions.Multiline | RegexOptions.AnyNewLine);

Esse recurso ajuda quando o texto vem de sistemas operacionais ou formatos de arquivo diferentes, em que o tipo de quebra de linha varia. Além da nova flag, a versão inclui melhorias no otimizador para padrões comuns de regex.

Breaking changes do .NET 11 Preview 3

O .NET 11 Preview 3 introduz quatro breaking changes nas bibliotecas. Todas são mudanças de comportamento, ou seja, o código compila igual, mas pode agir de outro jeito em tempo de execução.

CRC32 no ZipArchive

A primeira e mais impactante é a validação de CRC32 no ZipArchive. Arquivos ZIP corrompidos ou truncados que antes passavam sem erro agora podem lançar InvalidDataException.

Se o código depende de leitura tolerante de ZIPs potencialmente inválidos, revise o tratamento de erros. Por exemplo, capture a exceção e registre qual entrada falhou, em vez de deixar o processo inteiro cair.

Falhas em BackgroundService

A segunda mudança afeta o BackgroundService. Segundo as notas, exceções não tratadas agora param o host, em vez de serem engolidas silenciosamente.

A documentação de breaking changes detalha o ponto exato. Com BackgroundServiceExceptionBehavior.StopHost, que é o padrão desde o .NET 6, as tarefas de RunAsync, StopAsync e WaitForShutdownAsync agora falham com a exceção, em vez de concluir com sucesso.

Na prática, a aplicação passa a sair com código de erro, e não com zero. Se vários serviços falharem, as exceções chegam combinadas em um AggregateException.

A recomendação oficial é não fazer nada, porque uma aplicação que falhou não deve sair com sucesso. Se você precisa manter o comportamento anterior, envolva o RunAsync em um try/catch:

using Microsoft.Extensions.Hosting;

IHost host = Host.CreateApplicationBuilder(args).Build();

try
{
    await host.RunAsync();
}
catch (Exception ex)
{
    // Registra a falha do serviço em segundo plano
    Console.WriteLine($"Host stopped: {ex.Message}");
}

Se o tema for novo para você, o artigo sobre Background Services em C# e .NET explica o modelo de serviços hospedados.

Download AIA e TarWriter

A terceira mudança desabilita por padrão o download de certificados via AIA quando o SslStream, como servidor, valida certificados de cliente. Isso vale apenas quando não há uma CertificateChainPolicy customizada.

O motivo é desempenho e segurança, já que um servidor AIA lento travava o handshake e um atacante podia influenciar quais endpoints o servidor contatava. Para resolver, faça o cliente enviar a cadeia completa ou forneça os intermediários pelo ExtraStore da política do servidor.

A quarta mudança altera o TarWriter. Agora, quando o mesmo arquivo com hard link é arquivado mais de uma vez, ele emite entradas do tipo HardLink, em vez de duplicar o conteúdo.

Correções de bugs no .NET 11 Preview 3

Além das novas funcionalidades, a versão inclui correções importantes.

Na injeção de dependência, dependências circulares baseadas em factories agora lançam InvalidOperationException com uma mensagem clara. Antes, a falha vinha com um erro pouco útil para o diagnóstico.

No logging, o source generator agora suporta métodos genéricos. Assim, o logging de alto desempenho via ILogger alcança mais cenários.

Na camada de rede, o HttpListener no Windows ganhou controle sobre o buffering de respostas do kernel via HTTP.sys. Isso pode ser útil em cenários de streaming de respostas HTTP.

Como avaliar o impacto antes de migrar

Antes de apontar um projeto para o .NET 11 Preview 3, vale fazer um levantamento rápido. A maior parte das mudanças é aditiva, mas as breaking changes pedem uma busca direcionada no código.

Primeiro, procure todos os pontos que leem arquivos ZIP com ZipArchive ou ZipFile. Em seguida, verifique se eles tratam InvalidDataException e se existe algum fluxo que aceita arquivos vindos de fontes pouco confiáveis.

Depois, revise os serviços que herdam de BackgroundService. Confirme se o ExecuteAsync trata as próprias exceções e se o seu orquestrador, como um container ou um serviço do Windows, reage bem a um código de saída diferente de zero.

Também confira se algum servidor valida certificados de cliente com SslStream ou Kestrel. Nesse caso, garanta que os clientes enviam a cadeia completa de certificados intermediários.

Por fim, rode a suíte de testes no SDK do preview e compare os resultados com a versão atual. Esse cuidado evita surpresas quando a versão final chegar em novembro.

Como experimentar o .NET 11 Preview 3

Para testar o .NET 11 Preview 3, instale o SDK correspondente pelo site oficial do .NET. No Windows, a Microsoft recomenda a versão mais recente do Visual Studio 2026 Insiders.

No macOS e no Linux, o Visual Studio Code com a extensão C# Dev Kit oferece suporte ao .NET 11. Em seguida, basta ajustar o TargetFramework do projeto para net11.0.

Por se tratar de um preview, ele não é recomendado para produção. No entanto, ele serve bem para avaliação, migração experimental e testes de compatibilidade.

Conclusão

O .NET 11 Preview 3 avança em direções concretas e pragmáticas. As melhorias no System.Text.Json reduzem boilerplate sem sacrificar a legibilidade.

A consolidação do Zstandard no namespace certo sinaliza que a API está madura para fazer parte da BCL sem pacote separado. Enquanto isso, as expansões em I/O atendem quem trabalha perto do sistema operacional, e a flag de Regex resolve um problema antigo com quebras de linha.

As breaking changes, sobretudo o CRC32 e o BackgroundService, podem exigir ajustes, mas tornam a plataforma mais previsível e confiável. Com o lançamento previsto para novembro de 2026, o .NET 11 Preview 3 mostra que cada iteração adiciona valor tangível ao ecossistema.

FAQ

O .NET 11 é uma versão LTS?

Não. O .NET 11 é STS e, pela política atual, recebe 24 meses de suporte; para suporte mais longo, o .NET 10 LTS é a escolha recomendada.

Preciso remover alguma dependência ao migrar para o Preview 3?

Sim. Se você usava o pacote System.IO.Compression.Zstandard de previews anteriores, remova-o do .csproj, pois a API agora faz parte do SDK.

O JsonIgnore no nível da classe substitui o JsonSerializerOptions?

São abordagens complementares. O atributo define o padrão daquele tipo, e as opções continuam valendo para configurações globais ou tipos que você não pode alterar.

A validação de CRC32 pode quebrar meu código?

Sim, se o código depende de leitura tolerante de arquivos ZIP corrompidos. Revise o tratamento de InvalidDataException em todo código que lê ZIPs.

O que muda na prática com o BackgroundService?

Quando um serviço falha e o host para, o RunAsync agora lança a exceção e a aplicação sai com código de erro. A boa prática é tratar exceções dentro do ExecuteAsync.

Quando sai a versão final do .NET 11?

O lançamento está previsto para novembro de 2026, seguindo o ciclo anual do .NET.