<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gustavo Cremonez</title>
    <description>The latest articles on DEV Community by Gustavo Cremonez (@gustavo_cremonez).</description>
    <link>https://dev.to/gustavo_cremonez</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2082757%2F2cb7f49f-0653-46cd-892a-fa091c34d06a.jpeg</url>
      <title>DEV Community: Gustavo Cremonez</title>
      <link>https://dev.to/gustavo_cremonez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gustavo_cremonez"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Gustavo Cremonez</dc:creator>
      <pubDate>Wed, 04 Jun 2025 16:36:06 +0000</pubDate>
      <link>https://dev.to/gustavo_cremonez/-2pm2</link>
      <guid>https://dev.to/gustavo_cremonez/-2pm2</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/gustavo_cremonez/padrao-unit-of-work-o-coordenador-de-transacoes-em-aplicacoes-net-2mn1" class="crayons-story__hidden-navigation-link"&gt;Padrão Unit of Work: O Coordenador de Transações em Aplicações .NET&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/gustavo_cremonez" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2082757%2F2cb7f49f-0653-46cd-892a-fa091c34d06a.jpeg" alt="gustavo_cremonez profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/gustavo_cremonez" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Gustavo Cremonez
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Gustavo Cremonez
                
              
              &lt;div id="story-author-preview-content-2558991" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/gustavo_cremonez" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2082757%2F2cb7f49f-0653-46cd-892a-fa091c34d06a.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Gustavo Cremonez&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/gustavo_cremonez/padrao-unit-of-work-o-coordenador-de-transacoes-em-aplicacoes-net-2mn1" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 4 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/gustavo_cremonez/padrao-unit-of-work-o-coordenador-de-transacoes-em-aplicacoes-net-2mn1" id="article-link-2558991"&gt;
          Padrão Unit of Work: O Coordenador de Transações em Aplicações .NET
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/backend"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;backend&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/beginners"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;beginners&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/gustavo_cremonez/padrao-unit-of-work-o-coordenador-de-transacoes-em-aplicacoes-net-2mn1" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;3&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/gustavo_cremonez/padrao-unit-of-work-o-coordenador-de-transacoes-em-aplicacoes-net-2mn1#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>backend</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Padrão Unit of Work: O Coordenador de Transações em Aplicações .NET</title>
      <dc:creator>Gustavo Cremonez</dc:creator>
      <pubDate>Wed, 04 Jun 2025 13:34:02 +0000</pubDate>
      <link>https://dev.to/gustavo_cremonez/padrao-unit-of-work-o-coordenador-de-transacoes-em-aplicacoes-net-2mn1</link>
      <guid>https://dev.to/gustavo_cremonez/padrao-unit-of-work-o-coordenador-de-transacoes-em-aplicacoes-net-2mn1</guid>
      <description>&lt;p&gt;&lt;strong&gt;O Desafio da Gestão Transacional&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Em sistemas corporativos, operações que envolvem múltiplas entidades - como registrar um pedido, debitar estoque e atualizar o histórico do cliente - precisam ser tratadas como uma única unidade lógica. O padrão Unit of Work surge como solução para esse desafio, atuando como um orquestrador de transações que garante a integridade dos dados mesmo em cenários complexos.&lt;/p&gt;

&lt;p&gt;Neste artigo, exploraremos os fundamentos desse padrão, seu papel na arquitetura de software moderna e como ele se relaciona com outros conceitos como o Repository Pattern e Domain-Driven Design.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;A Essência do Padrão Unit of Work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O Unit of Work (UoW) é muito mais do que uma simples abstração técnica - é um padrão comportamental que organiza como as operações de persistência são gerenciadas em sistemas complexos. Para entender sua essência, vamos decompô-lo em princípios fundamentais:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Atomicidade como Filosofia Central&lt;/strong&gt;&lt;br&gt;
O UoW materializa o princípio ACID de atomicidade no nível de aplicação:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agrupa operações (inserts, updates, deletes) em uma única unidade lógica;&lt;/li&gt;
&lt;li&gt;Garante tudo ou nada: Todas as operações são confirmadas ou nenhuma é persistida;&lt;/li&gt;
&lt;li&gt;Exemplo prático: Em um sistema bancário, transferências entre contas só são completas se débito e crédito forem ambos bem-sucedidos;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rastreamento Inteligente de Estado&lt;/strong&gt;&lt;br&gt;
Um UoW eficiente atua como "memória transacional":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mantém registro de todas as entidades modificadas durante uma operação;&lt;/li&gt;
&lt;li&gt;Conhece o estado original e as alterações pendentes;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Coordenação de Recursos Múltiplos&lt;/strong&gt;&lt;br&gt;
Em arquiteturas modernas, o UoW evoluiu para lidar com:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Múltiplos bancos de dados (SQL + NoSQL)&lt;/li&gt;
&lt;li&gt;Sistemas distribuídos (microserviços com seus próprios repositórios)&lt;/li&gt;
&lt;li&gt;Fontes heterogêneas (banco de dados + filas + APIs externas)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Controle de Vida Útil (Lifetime Management)&lt;/strong&gt;&lt;br&gt;
O UoW gerencia o ciclo de vida das operações:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Início: Quando a unidade de trabalho é instanciada&lt;/li&gt;
&lt;li&gt;Registro: Operações são adicionadas ao contexto&lt;/li&gt;
&lt;li&gt;Validação: Verificação de consistência antes do commit&lt;/li&gt;
&lt;li&gt;Persistência: Escrita no(s) armazenamento(s)&lt;/li&gt;
&lt;li&gt;Finalização: Liberação de recursos (sucesso ou falha)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8a7ggwafyi9mjwpmndf4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8a7ggwafyi9mjwpmndf4.png" alt="Image description'diagrama com fluxo de operações com arquitura unit of work'" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Elementos Constituintes Fundamentais&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Um Unit of Work bem projetado possui três componentes essenciais:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contexto de Operações&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Função: Contêiner que agrega todas as mudanças pendentes&lt;/li&gt;
&lt;li&gt;Implementação: Normalmente um objeto que rastreia:

&lt;ul&gt;
&lt;li&gt;Novas entidades para inserir&lt;/li&gt;
&lt;li&gt;Entidades modificadas para atualizar&lt;/li&gt;
&lt;li&gt;Entidades marcadas para exclusão&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Mecanismo de Commit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Responsabilidade: Executar todas as operações pendentes de forma atômica&lt;/li&gt;
&lt;li&gt;Complexidade: Varia de simples (um banco) a complexo (sagas distribuídas)&lt;/li&gt;
&lt;li&gt;Garantias: Deve assegurar idempotência em caso de retentativas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Estratégia de Rollback&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Necessidade: Restaurar o estado consistente em caso de falha&lt;br&gt;
Abordagens comuns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compensação (operações inversas)&lt;/li&gt;
&lt;li&gt;Mecanismos ORM (change tracking reversal)&lt;/li&gt;
&lt;li&gt;Transações distribuídas (two-phase commit)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Unit of Work em Harmonia com Outros Padrões&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A Sinfonia com o Repository Pattern&lt;/strong&gt;
O Unit of Work e o Repository são parceiros naturais em arquiteturas robustas. Enquanto o Repository atua como uma coleção especializada para entidades específicas (como um bibliotecário que conhece cada prateleira), o Unit of Work é o gerente que coordena todas as operações do sistema. Juntos, formam uma dupla poderosa:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Repositórios fornecem acesso granular a entidades individuais:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;customerRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;123&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;orderRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newOrder&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Unit of Work orquestra múltiplos repositórios em uma transação unificada:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;uow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unitOfWorkFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;uow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;uow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;uow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Atomicidade garantida&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa simbiose permite que operações complexas (ex: transferir saldo entre contas) mantenham consistência sem expor detalhes de persistência ao domínio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Integração com Domain-Driven Design (DDD)&lt;/strong&gt;&lt;br&gt;
No DDD, o Unit of Work torna-se o guardião da integridade do agregado:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Preservação de Invariantes: Garante que regras de negócio complexas (ex: "limite de crédito não pode ser negativo") sejam validadas antes do commit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alinhamento com Bounded Contexts: Cada contexto delimitado pode ter sua própria implementação de UoW, respeitando fronteiras estratégicas:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqh6ktj4sd79tu88kr8ev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqh6ktj4sd79tu88kr8ev.png" alt="Image description'Diagrama que representa UoW com DDD'" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suporte a Domain Events: Coordena a publicação de eventos após o commit bem-sucedido:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;uow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Persiste dados&lt;/span&gt;
&lt;span class="n"&gt;eventDispatcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Dispara eventos&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Conclusão: O Maestro das Transações Complexas&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O Unit of Work transcende sua função técnica para tornar-se um pilar arquitetural essencial em sistemas onde integridade é não negociável. Sua verdadeira força revela-se quando combinado com padrões como Repository e DDD:&lt;/p&gt;

&lt;p&gt;Para Repository: É o maestro que transforma solos individuais (operações em repositórios) em uma sinfonia coesa (transações complexas).&lt;/p&gt;

&lt;p&gt;Para DDD: É o guardião que protege as invariantes do domínio e materializa intenções de negócio em operações atômicas.&lt;/p&gt;

&lt;p&gt;Em cenários modernos - de microsserviços a arquiteturas orientadas a eventos - o Unit of Work evoluiu para orquestrar não apenas bancos de dados, mas serviços distribuídos, filas de mensagens e APIs externas. Sua implementação requer equilíbrio entre rigor transacional e flexibilidade, mas quando bem executada, torna-se a base invisível que sustenta sistemas resilientes e confiáveis.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>backend</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Padrão Repository: A Abstração que Transformou o Acesso a Dados em Aplicações .NET</title>
      <dc:creator>Gustavo Cremonez</dc:creator>
      <pubDate>Sat, 24 May 2025 10:55:02 +0000</pubDate>
      <link>https://dev.to/gustavo_cremonez/padrao-repository-a-abstracao-que-transformou-o-acesso-a-dados-em-aplicacoes-net-21pn</link>
      <guid>https://dev.to/gustavo_cremonez/padrao-repository-a-abstracao-que-transformou-o-acesso-a-dados-em-aplicacoes-net-21pn</guid>
      <description>&lt;p&gt;No desenvolvimento de software moderno, uma das decisões mais críticas é como estruturar o acesso a dados. O padrão Repository emergiu como uma das soluções mais elegantes para este desafio, criando uma camada de abstração entre sua lógica de negócios e os mecanismos de armazenamento. Neste artigo, vamos explorar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O que é o padrão Repository e por que ele foi criado;&lt;/li&gt;
&lt;li&gt;Como ele se diferencia de outras abordagens;&lt;/li&gt;
&lt;li&gt;Seu relacionamento com outros padrões como Unit of Work;&lt;/li&gt;
&lt;li&gt;Quando usar (e quando não usar) esta abordagem;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Nos primórdios do desenvolvimento de aplicações, o acesso a dados era frequentemente implementado de forma direta e desestruturada. Os desenvolvedores escreviam queries SQL diretamente nos controllers, resultando em:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alto acoplamento: A lógica de negócios ficava intimamente ligada ao esquema do banco de dados;&lt;/li&gt;
&lt;li&gt;Dificuldade de teste: Era complexo isolar componentes para testes unitários;&lt;/li&gt;
&lt;li&gt;Falta de padronização: Diferentes partes do sistema acessavam dados de formas distintas;&lt;/li&gt;
&lt;li&gt;Complexidade na manutenção: Mudanças no esquema do banco exigiam alterações em múltiplos pontos do código;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Exemplo do problema: acesso direto a dados no controller&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProdutoController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Listar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * FROM Products"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;View&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O padrão Repository foi formalizado como parte do Domain-Driven Design (DDD) por Eric Evans em seu livro seminal de 2004. A ideia central era:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Fornecer uma abstração de coleção em memória para objetos de domínio, escondendo os detalhes de como e onde esses objetos são persistidos."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Esta abordagem trouxe vários benefícios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Separação de preocupações: A lógica de negócios não precisa saber como os dados são armazenados;&lt;/li&gt;
&lt;li&gt;Testabilidade: Podemos facilmente mockar o Repository para testes unitários;&lt;/li&gt;
&lt;li&gt;Flexibilidade: A fonte de dados pode ser trocada sem afetar o domínio;&lt;/li&gt;
&lt;li&gt;Consistência: Todas as operações de dados seguem o mesmo padrão;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;O padrão Repository ocupa um espaço único no ecossistema de acesso a dados, diferenciando-se significativamente de outras abordagens comuns. Para entender seu valor, vamos contrastá-lo com três alternativas principais:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository vs Acesso Direto ao Banco&lt;/strong&gt;&lt;br&gt;
Antes da popularização dos ORMs, era comum ver aplicações acessando bancos de dados diretamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Abordagem tradicional sem Repository&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Cliente&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetClientesPremium&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Cliente&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"SELECT * FROM Clientes WHERE Premium = 1"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Problemas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL hardcoded em toda a aplicação;&lt;/li&gt;
&lt;li&gt;Difícil manutenção quando o esquema muda;&lt;/li&gt;
&lt;li&gt;Quase impossível de testar unitariamente;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O Repository resolve isso encapsulando todas as operações de dados em uma única camada.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository vs ORM Direto (Entity Framework Core)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Muitos desenvolvedores questionam: "Por que usar Repository se o EF Core já é uma abstração?"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Uso direto do DbContext (sem Repository)&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProdutoService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProdutoService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Produto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetProdutosEmEstoque&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Produtos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Estoque&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Diferenças chave:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Nível de abstração: Repository esconde completamente o ORM usado;&lt;/li&gt;
&lt;li&gt;Flexibilidade: Facilita trocar EF por Dapper ou outro ORM;&lt;/li&gt;
&lt;li&gt;Contrato explícito: Interface do Repository define claramente as operações disponíveis;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Repository vs Micro ORMs (Dapper)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enquanto Dapper é excelente para performance, ele não oferece:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abstração de operações CRUD;&lt;/li&gt;
&lt;li&gt;Gerenciamento de estado;&lt;/li&gt;
&lt;li&gt;Fácil substituição por outra tecnologia;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O Repository adiciona essa camada organizacional.&lt;/p&gt;




&lt;p&gt;O Repository raramente trabalha sozinho. Ele faz parte de um ecossistema de padrões:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository + Unit of Work&lt;/strong&gt;&lt;br&gt;
A combinação mais clássica e poderosa:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbairxoyserfjihv6h7h1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbairxoyserfjihv6h7h1.png" alt="Image description 'Diagrama do padrão repository junto com unit of work'" width="800" height="1077"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vantagens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controle transacional centralizado;&lt;/li&gt;
&lt;li&gt;Coordenação entre múltiplos repositories;&lt;/li&gt;
&lt;li&gt;Padronização de operações de persistência;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Repository + Specification Pattern&lt;/strong&gt;&lt;br&gt;
Para queries complexas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ISpecification&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Expression&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Criteria&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Expression&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Includes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProdutosEmEstoqueSpec&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ISpecification&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Produto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Expression&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Produto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Criteria&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Estoque&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Expression&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Produto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Includes&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Categoria&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Repository + CQRS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Em arquiteturas mais avançadas:&lt;br&gt;
[Command Side] → [Repository] → [Banco de Dados]&lt;br&gt;
[Query Side] → [Queries Diretas] → [Cache/Read Model]&lt;/p&gt;




&lt;p&gt;Casos Ideais para Repository&lt;/p&gt;

&lt;p&gt;Para ajudar a decidir quando o padrão Repository é a escolha certa, veja este fluxograma de decisão:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0bjg2c3tgvueta6s54v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0bjg2c3tgvueta6s54v.png" alt="Image description 'Diagrama indicando quando usar e quando não usar o padrão'" width="800" height="958"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;O padrão Repository, quando aplicado corretamente, oferece:&lt;/p&gt;

&lt;p&gt;✔ Separação clara de responsabilidades;&lt;br&gt;
✔ Flexibilidade tecnológica;&lt;br&gt;
✔ Testabilidade aprimorada;&lt;br&gt;
✔ Manutenibilidade a longo prazo;&lt;/p&gt;

&lt;p&gt;Porém, como qualquer padrão, não é uma solução universal. A chave está em:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Avaliar as necessidades reais do projeto;&lt;/li&gt;
&lt;li&gt;Implementar de forma moderada;&lt;/li&gt;
&lt;li&gt;Manter o foco no domínio;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Em projetos .NET modernos, uma abordagem equilibrada pode ser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usar Repository para operações de escrita/comando;&lt;/li&gt;
&lt;li&gt;Usar abordagens mais diretas (Dapper, queries) para leitura;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Referências Úteis&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design" rel="noopener noreferrer"&gt;📌 Repository Pattern (Microsoft Docs)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://martinfowler.com/eaaCatalog/repository.html" rel="noopener noreferrer"&gt;📌 Repository Pattern (Martin Fowler)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E você? Como tem utilizado o padrão Repository em seus projetos? Compartilhe suas experiências nos comentários!&lt;/p&gt;

</description>
      <category>ddd</category>
      <category>repositorypattern</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>O que são Middlewares em APIs .NET?</title>
      <dc:creator>Gustavo Cremonez</dc:creator>
      <pubDate>Mon, 19 May 2025 16:55:27 +0000</pubDate>
      <link>https://dev.to/gustavo_cremonez/o-que-sao-middlewares-em-apis-net-1i</link>
      <guid>https://dev.to/gustavo_cremonez/o-que-sao-middlewares-em-apis-net-1i</guid>
      <description>&lt;p&gt;Se você já trabalhou com APIs em .NET, provavelmente já ouviu falar sobre Middlewares. Mas afinal, o que são e por que são tão importantes?&lt;/p&gt;

&lt;p&gt;Neste artigo, vamos explorar o conceito de Middlewares no contexto de APIs .NET, entender como eles funcionam e ver exemplos práticos de como utilizá-los.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que são Middlewares?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Middlewares são componentes que formam o pipeline de processamento de requisições em uma aplicação .NET. Eles são responsáveis por lidar com solicitações HTTP (requests) e respostas HTTP (responses), permitindo executar lógicas antes e depois que uma requisição chegue ao seu endpoint final.&lt;/p&gt;

&lt;p&gt;Pense em um middleware como uma "camada" que a requisição passa antes de chegar ao seu destino (e também na volta, quando a resposta é enviada ao cliente).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogia do Middleware&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine um restaurante:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Você faz um pedido (request).&lt;/li&gt;
&lt;li&gt;Antes de chegar ao cozinheiro (sua API Controller), o pedido passa pelo garçom, que verifica se está completo (middleware de validação).&lt;/li&gt;
&lt;li&gt;Depois de pronto, o prato (response) pode passar por outro garçom que adiciona temperos extras (middleware de transformação).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada middleware tem uma função específica e pode interromper o fluxo se necessário.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Como os Middlewares Funcionam no .NET?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No .NET, o pipeline de middlewares é configurado no arquivo Program.cs, usando o método Use, Run ou Map.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo Básico de Middleware&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Middleware 1: Logging&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Requisição recebida: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Chama o próximo middleware&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Middleware 2: Autorização&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ContainsKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;401&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Não autorizado"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Interrompe o pipeline&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Rota principal&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste exemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O primeiro middleware registra o caminho da requisição.&lt;/li&gt;
&lt;li&gt;O segundo middleware verifica se há um header de autorização. Se não houver, retorna 401 Unauthorized.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se tudo estiver correto, a requisição chega ao endpoint principal (/).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Middlewares Comuns no .NET&lt;/strong&gt;&lt;br&gt;
O .NET já possui vários middlewares prontos para uso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UseRouting()          Define o roteamento da aplicação.&lt;/li&gt;
&lt;li&gt;UseAuthentication()   Habilita autenticação.&lt;/li&gt;
&lt;li&gt;UseAuthorization()    Habilita autorização.&lt;/li&gt;
&lt;li&gt;UseCors()         Configura políticas CORS.&lt;/li&gt;
&lt;li&gt;UseStaticFiles()  Permite servir arquivos estáticos (HTML, CSS, JS).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exemplo com Middlewares Integrados&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseRouting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/secure"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Rota segura!"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;RequireAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;A Ordem Importa!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No .NET, a sequência em que os middlewares são registrados no Program.cs define a ordem de execução. Isso é crucial, pois um middleware pode depender do processamento de outro. Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseHttpsRedirection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 1º: Redireciona para HTTPS  &lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseStaticFiles&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      &lt;span class="c1"&gt;// 2º: Serve arquivos estáticos (CSS, JS)  &lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseRouting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;         &lt;span class="c1"&gt;// 3º: Define as rotas  &lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// 4º: Autentica o usuário  &lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// 5º: Verifica as permissões  &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se você inverter UseRouting e UseAuthentication, a autenticação não funcionará, pois o roteamento ainda não terá identificado o endpoint a ser protegido.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Quando Criar um Middleware Personalizado?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Você pode criar um middleware personalizado quando:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Precisa validar algo em todas as requisições (ex: checar API Key).&lt;/li&gt;
&lt;li&gt;Quer loggar todas as requisições/respostas.&lt;/li&gt;
&lt;li&gt;Precisa transformar respostas (ex: adicionar headers customizados).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Um uso comum é centralizar o tratamento de exceções para evitar repetição de código:&lt;/p&gt;

&lt;p&gt;Middleware de Tratamento de Erros:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseExceptionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorApp&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;  
&lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;errorApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;  
    &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Features&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IExceptionHandlerFeature&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;  
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsJsonAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;  
        &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ocorreu um erro inesperado."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="n"&gt;Details&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;  
        &lt;span class="p"&gt;});&lt;/span&gt;  
    &lt;span class="p"&gt;});&lt;/span&gt;  
&lt;span class="p"&gt;});&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Impacto na Performance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Middlewares adicionam overhead ao pipeline. Para evitar gargalos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use middlewares leves (ex.: evite processamento bloqueante).&lt;/li&gt;
&lt;li&gt;Registre apenas os necessários (em produção, desative logs detalhados).&lt;/li&gt;
&lt;li&gt;Considere UseWhen para aplicar middlewares condicionalmente:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseWhen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;appBuilder&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;  
&lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;appBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseMiddleware&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiSpecificMiddleware&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;  
&lt;span class="p"&gt;});&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Conclusão&lt;/strong&gt;&lt;br&gt;
Middlewares são peças fundamentais no desenvolvimento de APIs .NET, permitindo adicionar comportamentos personalizados ao pipeline de requisições. Eles podem ser usados para logging, autenticação, tratamento de erros e muito mais.&lt;/p&gt;

&lt;p&gt;Dominar middlewares ajuda a criar aplicações mais modulares, seguras e eficientes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referências Úteis&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/pt-br/aspnet/core/fundamentals/middleware/" rel="noopener noreferrer"&gt;Documentação Oficial&lt;/a&gt;: Middlewares no ASP.NET Core&lt;/p&gt;

&lt;p&gt;E aí, já usou middlewares em seus projetos? Conte nos comentários! 🚀&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>api</category>
      <category>middleware</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
