Pular para conteúdo

ASP.NET Web API e Azure (.NET)

Definição: ASP.NET Web API

ASP.NET Web API é o framework da plataforma .NET para criar serviços HTTP/REST. Na versão do livro-base (Web API 2, 2014, .NET Framework + IIS), as APIs eram uma peça separada; hoje o equivalente é o ASP.NET Core Web API (multiplataforma, open source), que mantém os mesmos conceitos: controladores, ações, rotas, serialização JSON e injeção de dependência.

Esta página reúne os conceitos reutilizáveis; os passos de tela do Visual Studio e do portal Azure da época estão obsoletos e foram omitidos. Para os princípios de REST, veja Backend; para a alternativa em Java, Spring.

Controladores, ações e rotas

  • Controller é a classe que trata requisições HTTP; seus métodos públicos são as actions. O framework mapeia o verbo HTTP e a URL para a ação (GET /api/produtos/5 → Get(5)).
  • Roteamento por convenção (padrão api/{controller}/{id}) ou por atributos ([Route("api/produtos/{id}")], [HttpGet]), que dá controle total e é o padrão atual.
  • Tipos de retorno: o tipo do domínio (o framework serializa em JSON/XML por content negotiation) ou um resultado HTTP que controla status e cabeçalhos: Ok(obj) (200), Created(...)/CreatedAtAction (201), NoContent() (204), BadRequest() (400), NotFound() (404), StatusCode(500).
  • Documentação: hoje por OpenAPI/Swagger (antes, páginas de ajuda e WADL), que também alimenta clientes gerados e testes com Postman.
[ApiController]
[Route("api/produtos")]
public class ProdutosController : ControllerBase
{
    private readonly LojaContext _db;
    public ProdutosController(LojaContext db) => _db = db;          // injeção de dependência

    [HttpGet]
    public async Task<IEnumerable<Produto>> Listar() => await _db.Produtos.ToListAsync();

    [HttpGet("{id:int}")]
    public async Task<ActionResult<Produto>> Obter(int id)
    {
        var p = await _db.Produtos.FindAsync(id);
        return p is null ? NotFound() : Ok(p);
    }

    [HttpPost]
    public async Task<ActionResult<Produto>> Criar(Produto p)       // [ApiController] já valida o modelo e devolve 400
    {
        _db.Produtos.Add(p);
        await _db.SaveChangesAsync();
        return CreatedAtAction(nameof(Obter), new { id = p.Id }, p);
    }
}

Persistência com Entity Framework

  • Entity Framework (EF) é o ORM da plataforma .NET (hoje EF Core). Abordagem Code First: você escreve as classes do modelo e o EF cria e evolui o banco por migrações.
  • Um DbContext representa a sessão com o banco e expõe DbSet<T> por tabela (equivalente ao EntityManager/repositórios do JPA, veja Acesso a dados).
  • Migrações: Add-Migration/dotnet ef migrations add gera o código da mudança; Update-Database/dotnet ef database update o aplica; o EF guarda o histórico em uma tabela (__EFMigrationsHistory) e executa só o que falta. Um método de seed popula dados iniciais.
  • LINQ e lambdas: consultas fortemente tipadas em C# que viram SQL (_db.Produtos.Where(p => p.Preco > 10).OrderBy(p => p.Nome)); evite trazer tudo para a memória antes de filtrar.

Validação do modelo

Atributos de Data Annotations nas propriedades: [Key] (chave primária), [Required] (obrigatório, com mensagem), [MaxLength]/[StringLength], [Range], [RegularExpression]. Com [ApiController] (ou checando ModelState.IsValid), requisições inválidas voltam 400 Bad Request com os erros por campo. Para regras mais ricas, FluentValidation (em Java, o equivalente é o Bean Validation, veja Spring).

Autenticação e autorização

  • Autenticação responde "quem é você?"; autorização, "o que pode fazer?". No livro, o OAuth 2.0 com Resource Owner Password e tokens do tipo bearer em um servidor de autorização embutido, com usuários e papéis (ADMIN, USER) em tabelas do ASP.NET Identity (AspNetUsers, AspNetRoles).
  • [Authorize] protege um controlador ou ação ([Authorize(Roles = "ADMIN")]); sem a anotação, nada é exigido mesmo com o mecanismo configurado (erro comum). [AllowAnonymous] abre exceções.
  • Hoje: JWT bearer com ASP.NET Core Identity ou provedores externos (Microsoft Entra ID/Azure AD, Keycloak), com fluxo authorization code + PKCE para clientes públicos (o grant password é desencorajado) (OAuth e JWT).

Roteamento avançado e integração

  • Novas operações em um serviço: rotas por atributo, parâmetros de rota/consulta/corpo ([FromBody], [FromQuery]), verbos próprios (/api/pedidos/{id}/cancelar).
  • Integração: consumir serviços SOAP (cliente gerado a partir do WSDL; exemplo clássico: cálculo de frete dos Correios) e REST (HttpClient, com IHttpClientFactory) de dentro de uma ação, útil em integração de sistemas (SOAP e REST). Use timeouts, retries e circuit breaker (Polly) (resiliência).

Publicando no Azure

  • Azure App Service hospeda a API (PaaS); o Azure SQL Database guarda os dados; o perfil de publicação ou, hoje, GitHub Actions/Azure DevOps fazem o deploy (CI/CD). As migrações podem rodar na publicação (opção Code First Migrations).
  • Monitoração e diagnóstico: log streaming, tracing da aplicação e métricas no portal; hoje Application Insights e OpenTelemetry (Observability). Configuração e segredos em App Settings e Key Vault, não no código.
  • Conceitos de PaaS, banco gerenciado e regiões em Nuvem.

.NET e C#: fundamentos da plataforma

Definição: .NET

.NET é a plataforma da Microsoft para criar aplicações (web, desktop, mobile, nuvem, jogos). Ela reúne linguagens (C#, F#, VB.NET), uma máquina virtual (o CLR, Common Language Runtime) e uma biblioteca de classes (BCL). A versão do livro-base (.NET Framework 3.5/4, 2008 a 2010, só Windows) evoluiu para o .NET moderno (.NET 6, 8, 9...), multiplataforma e de código aberto.

Como o código C# é executado

flowchart LR
    A["Código C#<br/>(.cs)"] -->|compilador| B["CIL / MSIL<br/>(assembly .dll/.exe)"]
    B -->|CLR + JIT| C["Código nativo<br/>da máquina"]
  • O compilador gera CIL (Common Intermediate Language), um código intermediário parecido com o bytecode do Java (JVM); o JIT o traduz para código nativo na execução. Há também AOT (compilação antecipada).
  • CTS (Common Type System) define os tipos comuns entre linguagens .NET, o que permite que um componente em C# seja usado em F# ou VB.NET. O coletor de lixo (GC) libera a memória automaticamente.
  • Um assembly é a unidade de distribuição e versionamento (.dll ou .exe); um namespace agrupa tipos e evita conflitos de nome; o using o importa.

Tipos: valor x referência

Aspecto Tipo de valor (struct, int, bool, enum) Tipo de referência (class, string, arrays, interface)
Armazenamento Normalmente na pilha (stack) ou embutido no objeto Objeto no heap; a variável guarda a referência
Atribuição Copia o valor Copia a referência (dois nomes para o mesmo objeto)
Nulo Não aceita null, a menos que seja int? (nullable) Aceita null (veja nullable reference types)

Boxing é converter um valor em object (aloca no heap) e unboxing é o caminho inverso; ambos têm custo. Strings são imutáveis: concatenar muito em loop cria muitos objetos, então use StringBuilder.

A linguagem C# em um exemplo

public interface IDesconto { decimal Calcular(decimal valor); }

public class DescontoFixo : IDesconto
{
    private readonly decimal _percentual;                    // campo privado, imutável após o construtor
    public DescontoFixo(decimal percentual) => _percentual = percentual;
    public decimal Calcular(decimal valor) => valor * _percentual / 100;
}

public class Pedido
{
    public int Id { get; init; }                             // propriedade auto-implementada (get/set sem código extra)
    public List<decimal> Itens { get; } = new();
    public decimal Total => Itens.Sum();                     // propriedade calculada (expression-bodied)

    public decimal TotalCom(IDesconto desconto) => Total - desconto.Calcular(Total);
}

var pedido = new Pedido { Id = 1 };
pedido.Itens.AddRange(new[] { 50m, 70m });
Console.WriteLine($"Total: {pedido.TotalCom(new DescontoFixo(10)):C}");     // interpolação e formato de moeda
  • Propriedades (get/set/init) substituem os getters e setters manuais do Java; record cria tipos imutáveis com igualdade por valor (equivalente ao record do Java moderno).
  • Orientação a objetos: classes, herança (: ClasseBase), virtual/override, abstract, interfaces e modificadores public, private, protected, internal (visível no assembly). Veja a teoria em Orientação a Objetos.
  • Tratamento de erros: try/catch/finally e throw; using garante a liberação de recursos que implementam IDisposable (como o try-with-resources do Java). Prefira capturar exceções específicas.
  • Genéricos e coleções: List<T>, Dictionary<K,V>, HashSet<T>; var infere o tipo local.
  • Delegates, lambdas e eventos: delegate é um tipo que representa uma função (Func<>, Action<>); lambdas (x => x * 2) e eventos (padrão observer, ver Padrões) se apoiam nele.
  • LINQ consulta qualquer coleção (ou banco, via Entity Framework) com sintaxe parecida com SQL: itens.Where(i => i > 50).OrderBy(i => i).Select(i => i * 2).
  • async/await escreve código assíncrono de forma sequencial, sobre Task: libera a thread durante esperas de I/O e é a base de qualquer API ASP.NET Core moderna.

Acesso a dados: do ADO.NET ao Entity Framework

ADO.NET é a camada base de acesso a bancos no .NET, equivalente ao JDBC do Java (Acesso a dados):

Objeto ADO.NET Papel Equivalente em JDBC
SqlConnection Abre a conexão (string de conexão) Connection
SqlCommand Executa SQL ou procedimento; aceita parâmetros PreparedStatement
SqlDataReader Lê o resultado linha a linha, só para frente, conectado ResultSet
DataSet/DataAdapter Cópia desconectada dos dados em memória (não há equivalente direto)
using var conexao = new SqlConnection(stringDeConexao);
await conexao.OpenAsync();
using var cmd = new SqlCommand("SELECT Nome FROM Cliente WHERE Id = @id", conexao);
cmd.Parameters.AddWithValue("@id", 42);          // parâmetros evitam SQL Injection
using var leitor = await cmd.ExecuteReaderAsync();
while (await leitor.ReadAsync()) Console.WriteLine(leitor.GetString(0));

Hoje o caminho usual é o Entity Framework (ORM, seção "Persistência com Entity Framework"), ou o Dapper (micro-ORM leve) quando se quer controlar o SQL.

Aplicações desktop e web no .NET: o que é legado

Tecnologia da época Situação Substituto atual
Windows Forms / WPF Ainda usadas em desktop Windows WPF, WinUI, MAUI (multiplataforma)
ASP.NET Web Forms (eventos e ViewState, páginas .aspx) Legado; só manutenção ASP.NET Core MVC, Razor Pages, Blazor
VB.NET Mantida, sem novos recursos de linguagem C#
.NET Framework (só Windows) Só correções de segurança .NET moderno (multiplataforma)

Para responder em entrevista

Pergunta Ideias para a resposta
"O que é uma action e como o roteamento funciona?" Método público do controller; mapeado por verbo HTTP + rota (convenção ou atributos)
"Code First e migrações?" Modelo em classes gera/evolui o banco; migrações versionam o esquema e aplicam só o pendente
"Como proteger uma API?" [Authorize] com JWT/OAuth2, papéis ou políticas; HTTPS; validação de entrada; segredos no Key Vault
"Diferença entre Web API e ASP.NET Core?" Web API 2 (.NET Framework, IIS) é o antecessor; Core é multiplataforma, modular, com DI embutida e Kestrel
"Como evitar N+1/consultas pesadas com EF?" Projeções, Include, filtrar no banco, paginação