Web Forms e Angular: a mudança de arquitetura na migração para .NET 10

TL;DR

  • Migrar Web Forms para Angular não é trocar controles de tela. É trocar a unidade de deploy.
  • No Web Forms, apresentação, processamento e dados vivem na mesma página, no mesmo processo, na mesma DLL.
  • Com Angular e .NET 10, a aplicação se divide em camadas independentes: front, API, aplicação, domínio, infraestrutura, banco.
  • O backend .NET 10 muda: Minimal APIs, controllers enxutos, Clean Architecture como default de mercado.
  • O front Angular muda: TypeScript, componentes, estado client-side, contratos de API como fronteira entre times.
  • DevOps muda junto: build separado, deploy independente, versionamento próprio por camada, contrato de API versionado.
  • O time muda: especialidades diferentes, ciclo de feedback curto no front, governança explícita do contrato.
  • A KW que resume a discussão toda é Diferenças entre Web Forms e Angular — porque a tecnologia é secundária; o que muda é a unidade de deploy, o ciclo de release e o perfil do time.
  • Migração bem feita migra arquitetura antes de migrar sintaxe. Trocar .aspx por .ts mantendo a mesma estrutura por baixo é a forma mais cara de fracassar.

~ 12 min de leitura · 2055 palavras

Por que Web Forms e Angular não são comparáveis como tecnologia

Comparar Web Forms e Angular pelo framework é comparar aviação a vapor com aviação a jato dizendo que “os dois voam”. Voam, mas o que muda não é o meio de transporte. É o que pode ser feito com ele.

Web Forms foi desenhado em 2002 para um problema real da época: arrastar um botão, conectar a um evento, salvar no banco, tudo na mesma página. Era produtividade radical. Funcionou por vinte anos exatamente porque casava com a infraestrutura e o perfil de sistema da época — aplicações internas, intranet, deploy em servidor único, time pequeno que conhecia toda a base.

Angular foi desenhado em 2016 (com a v2) para outro problema: front end complexo, estado rico, validação local, comunicação assíncrona com backends, times de UI e API trabalhando em paralelo. Ele não substitui Web Forms. Ele substitui a suposição de que a página é o centro do sistema.

A pergunta útil não é “qual framework é melhor”. É: o que muda na arquitetura do sistema quando o centro deixa de ser a página e passa a ser a API.

Como o Web Forms amarra tudo na mesma unidade

No Web Forms, a página é o sistema. Cada `.aspx` tem um ciclo de vida próprio:

  • Page Lifecycle com Init, Load, PreRender, Render, Unload.
  • ViewState escondido no HTML para “lembrar” o estado entre PostBacks.
  • PostBack enviando o formulário inteiro de volta para o servidor.
  • Code Behind com regras de negócio misturadas com a marcação da tela.
  • Server Controls que escondem o HTML e expõem propriedades C#.
  • Web Forms designers que tratam o .aspx como se fosse um formulário Visual Basic — e de fato era.

O resultado é uma unidade de deploy única: a DLL contém a página, o Code Behind, o acesso a dados, às vezes a regra de negócio, às vezes a stored procedure que persiste o registro. Tudo num arquivo, num assembly, num processo.

Em 2005 isso era elegante. Em 2026 isso é o problema. Porque quando tudo está junto:

  • A interface não pode mudar sem recompilar o backend.
  • O backend não pode escalar independentemente da interface.
  • Um bug de UI obriga deploy de uma DLL que toca regra de negócio.
  • Testar a interface exige rodar o servidor de aplicação.
  • Subir uma versão nova exige reiniciar o pool de IIS, o que derruba a sessão de todos os usuários simultaneamente.

A arquitetura Web Forms não é ruim por culpa do framework. É ruim porque a página virou a unidade de deploy, e a unidade de deploy virou a unidade organizacional — a equipe que mexe na página é a mesma que mexe no banco.

Como Angular e .NET 10 separam o sistema em camadas

As diferenças entre Web Forms e Angular ficam mais visíveis quando você coloca os dois lado a lado. O Web Forms trata a página como unidade de deploy e entrega HTML pronto para o navegador. O Angular trata a página como unidade de execução dentro de uma SPA que conversa com uma API por HTTP. Esse é o ponto que define o resto.

A partir daí, o resto da arquitetura se reorganiza.

As diferenças entre Web Forms e Angular ficam mais visíveis quando você coloca os dois lado a lado. O Web Forms trata a página como unidade de deploy e entrega HTML pronto para o navegador. O Angular trata a página como unidade de execução dentro de uma SPA que conversa com uma API por HTTP. Esse é o ponto que define o resto.

A partir daí, o resto da arquitetura se reorganiza.

O modelo Angular + .NET 10 nasce da constatação oposta: a unidade de deploy não pode ser a página. Cada camada tem seu próprio ritmo, sua própria escala, seu próprio time.

A divisão padrão de mercado em 2026 segue o seguinte esqueleto:

  • Front end (Angular). Componentes, serviços, estado, validação local, roteamento. Build produz arquivos estáticos servidos por CDN. Deploy é independente do backend.
  • API (ASP.NET Core / .NET 10). Endpoints REST ou gRPC, validação de entrada, autenticação, autorização. Sem regra de negócio. Stateless.
  • Camada de aplicação (Use Cases). Orquestra chamadas a domínio e infraestrutura. Traduz “a UI quer X” em “executar a operação Y”. É a única camada que conhece o caso de uso concreto.
  • Domínio (Entities + Regras de Negócio). Modelos do problema, regras que não dependem de banco nem de UI. Pura, testável sem framework.
  • Infraestrutura (Repositories, Gateways, Migrations). Persistência, integração com sistemas externos, filas, cache, log. Implementa contratos definidos pelo domínio.
  • Banco de dados. Estado persistente, schema versionado por migration, índices e constraints. Acessado exclusivamente via infraestrutura.

A consequência é que cada camada pode:

  • Ser deployada separadamente.
  • Escalar em ritmo próprio.
  • Ser mantida por times diferentes.
  • Ser testada isoladamente com mocks das outras camadas.
  • Ser reescrita sem mexer nas demais, desde que o contrato de API não mude.

A regra que vale gravar: o contrato de API é a fronteira. Tudo o que está dentro de uma camada é refatorável. O que está na fronteira é promessa pública.

O que muda no backend .NET 10

Para um dev que vem de Web Forms, o backend .NET 10 é quase irreconhevel. Não por causa da linguagem — C# continua sendo C# — mas por causa das camadas.

// Minimal API em .NET 10: handler enxuto, sem herança de Page, sem PostBack
app.MapPost("/api/pedidos", async (
    CriarPedidoRequest req,
    ICriarPedidoUseCase useCase,
    CancellationToken ct) =>
{
    var result = await useCase.ExecutarAsync(req, ct);
    return result.IsSuccess
        ? Results.Created($"/api/pedidos/{result.PedidoId}", result)
        : Results.BadRequest(result.Erros);
});

O handler não conhece Entity Framework. Não conhece `HttpContext`. Não conhece `Session`. Não conhece `ViewState`. Ele delega.

A lógica vive na camada de aplicação:

public class CriarPedidoUseCase(
    IPedidoRepository repo,
    IEstoqueGateway estoque,
    IUnitOfWork uow) : ICriarPedidoUseCase
{
    public async Task<Result<Pedido>> ExecutarAsync(
        CriarPedidoRequest req, CancellationToken ct)
    {
        // regra de negócio, validação de domínio, orquestração
        // ...
    }
}

E o acesso a dados vive na infraestrutura:

public class PedidoRepository(AppDbContext db) : IPedidoRepository
{
    public async Task<Pedido?> ObterAsync(Guid id, CancellationToken ct)
        => await db.Pedidos
            .Include(p => p.Itens)
            .FirstOrDefaultAsync(p => p.Id == id, ct);
}

Cada camada tem uma responsabilidade. Cada camada testa sozinha. Cada camada evolui no seu ritmo.

O que muda no front Angular

No Angular, a página deixou de ser o sistema. A página é a consequência da interação com o estado. Mudou o modelo mental inteiro.

// Componente de pedido, padrão atual Angular 18+ com signals
@Component({
  selector: 'app-pedido-form',
  standalone: true,
  imports: [ReactiveFormsModule],
  template: `
    <form [formGroup]="form" (ngSubmit)="salvar()">
      <input formControlName="clienteId" />
      <input formControlName="quantidade" type="number" />
      <button type="submit" [disabled]="form.invalid || saving()">
        {{ saving() ? 'Salvando...' : 'Salvar pedido' }}
      </button>
    </form>
  `
})
export class PedidoFormComponent {
  private api = inject(PedidoApi);
  saving = signal(false);
  form = inject(FormBuilder).group({
    clienteId: ['', Validators.required],
    quantidade: [1, [Validators.required, Validators.min(1)]],
  });

  salvar() {
    if (this.form.invalid) return;
    this.saving.set(true);
    this.api.criar(this.form.getRawValue()).subscribe({
      next: () => { this.saving.set(false); /* navegar */ },
      error: () => { this.saving.set(false); }
    });
  }
}

O componente não conhece o banco. Não conhece stored procedure. Não conhece `Server.Transfer`. Ele conhece o `PedidoApi`, que é a ponte para o backend. A interface pode ser redesenhada sem tocar na regra de negócio. A regra de negócio pode ser migrada de SQL para NoSQL sem tocar na interface.

Mais do que isso: o front pode ser hospedado em CDN,缓存ar no navegador, funcionar offline para leitura, pré-renderizar o primeiro carregamento. Tudo o que a página Web Forms, com seu PostBack obrigatório e ViewState no HTML, simplesmente não consegue fazer.

O que muda em DevOps

Quando a arquitetura muda, o pipeline de deploy muda junto. Em Web Forms, o ciclo é:

1. Compilar a DLL. 2. Copiar para o servidor IIS. 3. Reciclar o Application Pool. 4. Rezar para a sessão dos 200 usuários não se perder.

Em Angular + .NET 10, o ciclo é:

1. Build do front gera bundle estático. Upload para CDN. Cache invalidado. Deploy concluído em minutos. 2. Build do backend gera container. Push para registry. Rolling update em Kubernetes ou container app. Deploy sem derrubar sessão. 3. Migration do banco roda em job separado, com rollback planejado. 4. Contrato de API é versionado (v1, v2). Cliente consome v1 enquanto backend migra para v2. Compatibilidade de N versões mantida explicitamente.

A consequência operacional é grande: a frequência de deploy da UI pode ser diária, a do backend semanal, a do banco mensal. Cada time publica quando a feature está pronta, não quando “tudo está pronto”.

O que muda no time

Arquitetura é decisão organizacional disfarçada. A frase é do Conway, mas continua valendo.

Em Web Forms, normalmente o time é pequeno, multidisciplinar, com gente que mexe em tudo — aspx, code behind, SQL, IIS. Funciona até certo tamanho. Depois, vira gargalo: cada alteração obriga a mesma pessoa a mexer em cinco camadas diferentes, e o conhecimento vira ponto único de falha.

Em Angular + .NET 10, a divisão saudável costuma ser:

  • Time de front (Angular, UX, design system, acessibilidade).
  • Time de API (endpoints, autenticação, contratos, versionamento).
  • Time de domínio (regras de negócio, modelagem, testes de unidade).
  • Time de infraestrutura (banco, filas, observabilidade, deploy, SRE).

Esses times podem compartilhar pessoas no início, mas o trabalho de cada um tem contrato, ferramenta, build, deploy e SLO próprios.

Quando essa divisão não compensa

Arquitetura em camadas é boa default para sistemas que vão crescer, mas é exagero para sistemas pequenos. Casos em que a divisão completa não compensa:

  • Ferramenta interna com 5 usuários e 3 telas. Angular + .NET 10 com 5 camadas para 3 CRUDs é teatro de engenharia. Um monolito bem escrito resolve em 1/10 do tempo.
  • Script de migração one-shot. Não precisa de front. Não precisa de domínio. Não precisa de use case. Precisa rodar uma vez e morrer.
  • Protótipo de validação de hipótese. Antes de saber se o sistema vai existir daqui a 6 meses, a melhor arquitetura é a que coloca o produto na mão do usuário mais rápido. Over-engineering mata protótipos.
  • Integração entre dois sistemas legados. Se for um job que lê de um lado e grava no outro, Minimal API com um handler é o suficiente. Camadas a mais só atrasam.

A regra é simples: pague o custo de arquitetura proporcional ao tamanho, à duração esperada e à criticidade do sistema.

Os erros clássicos de migração

Tem três formas de errar a migração de Web Forms para Angular + .NET 10 que aparecem em quase todo projeto real.

Erro 1: trocar a casca mantendo a estrutura. Reescrever o .aspx como componente Angular, mas continuar chamando stored procedure direto, manter a regra de negócio no controller, expor Entity Framework como API. O resultado é um sistema com sintaxe nova e a mesma arquitetura por baixo. Pior que o original: agora tem dois mundos para manter.

Erro 2: começar pela UI. Migrar o front antes de definir o contrato de API. Aí o componente Angular chama endpoints que ainda não existem, ou endpoints que mudam a cada semana. O time de front fica travado esperando o backend, o time de backend fica refatorando para atender a UI que ainda não estabilizou.

Erro 3: ignorar o contrato de API. Tratar a API como detalhe de implementação, não como produto. Sem versionamento, sem documentação, sem testes de contrato. O resultado é que cada deploy do backend quebra o front em produção.

A ordem correta é: definir o contrato de API primeiro, validar com um mock, migrar o backend em paralelo, migrar o front consumindo o mock, substituir o mock pelo backend real no final.

Como vender a mudança de arquitetura para o time e a gestão

O argumento mais comum contra essa divisão é custo. “Vai demorar mais”, “vai ter mais código”, “o sistema é pequeno, não precisa disso tudo”.

A resposta prática é que o custo da arquitetura em camadas aparece cedo, mas o benefício aparece sempre. A reescrita anual, a refatoração de três meses, a dependência de uma pessoa que entende tudo, a indisponibilidade de 4 horas a cada deploy — tudo isso some quando o sistema está dividido em camadas independentes.

Para um ERP de 5 anos com 200 usuários, manter o Web Forms custa mais em 18 meses do que migrar com arquitetura em camadas. A conta é simples: refactor + bugfix + indisponibilidade + dificuldade de contratar > custo de migração planejada.

Para uma ferramenta interna de 3 telas com 5 usuários, a mesma arquitetura é desperdício. O cálculo inverte.

A pergunta que vale fazer antes de qualquer migração: quanto custa manter o sistema atual nos próximos 3 anos? Se o número for maior do que o custo de migrar com arquitetura em camadas, a migração compensa. Se for menor, fica onde está e moderniza aos poucos — começando pela exposição de APIs sobre o legado, sem mexer na interface.

O que vale guardar

Migrar Web Forms para Angular não é trocar controles de tela. É trocar a unidade de deploy, a fronteira entre times, o ciclo de release, o perfil de quem programa e a forma de pensar a regra de negócio.

O Web Forms não é ruim. É uma arquitetura que fez sentido por vinte anos e deixou de fazer. O Angular + .NET 10 é a resposta de mercado para sistemas que precisam escalar, versionar, integrar e sobreviver a mais de uma década de uso.

A migração bem feita migra arquitetura antes de migrar sintaxe. Quem troca o .aspx por .ts sem mexer na estrutura por baixo está pagando o custo do Angular sem receber o benefício. Quem migra arquitetura primeiro, mesmo que em uma única tela de cada vez, está construindo um sistema que vai envelhecer bem.

E isso vale mais do que o framework.

Posts Similares

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *