<?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>Forem: Inácio Bueno</title>
    <description>The latest articles on Forem by Inácio Bueno (@inacio88).</description>
    <link>https://forem.com/inacio88</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%2F2305117%2Fbe9fd2d2-c610-4af3-8bb3-bf3e7babe12b.jpg</url>
      <title>Forem: Inácio Bueno</title>
      <link>https://forem.com/inacio88</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/inacio88"/>
    <language>en</language>
    <item>
      <title>Playwright Codegen</title>
      <dc:creator>Inácio Bueno</dc:creator>
      <pubDate>Thu, 12 Feb 2026 04:27:58 +0000</pubDate>
      <link>https://forem.com/inacio88/playwright-codegen-1jb3</link>
      <guid>https://forem.com/inacio88/playwright-codegen-1jb3</guid>
      <description>&lt;p&gt;Playwright é uma das libs de teste end-to-end mais completas disponíveis no mercado: suporte aos principais navegadores, sistemas operacionais, pronto para desenvolvimento local e execução em pipelines de integração.&lt;br&gt;
Esse post não sobre playwight em si, mas sim uma ferramenta dessa lib que me ajudou demais fazendo testes de integração: &lt;strong&gt;&lt;em&gt;codegen&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
O que é a codegen? Resumindo bem, é uma ferramenta que grava toda a sua ação (clicks do mouse e ações no teclado) na aplicação que você quer testar. Então se você quer testar o fluxo de login, basta iniciar a codegen e fazer o fluxo como se você fosse um usuário comum fazendo login. É tudo tão simples assim? Não, mas é quase lá.&lt;/p&gt;
&lt;h2&gt;
  
  
  Instalação
&lt;/h2&gt;

&lt;p&gt;Se quiser acompanhar &lt;a href="https://playwright.dev/dotnet/docs/intro" rel="noopener noreferrer"&gt;está aqui o passo a passo&lt;/a&gt;:&lt;br&gt;
Crie um projeto; entra no diretório; instala o nuget; faz o build&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new xunit -n PlaywrightTests
cd PlaywrightTests
dotnet add package Microsoft.Playwright.Xunit
dotnet build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois do build, executa isso para instalar os navegadores&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pwsh bin/Debug/net8.0/playwright.ps1 install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uma alternativa a esse último passo, você pode fazer (não é muito recomendado pois é depreciado e em &lt;a href="https://www.nuget.org/packages/Microsoft.Playwright.CLI" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/Microsoft.Playwright.CLI&lt;/a&gt; recomenda você fazer pwsh bin/Debug/net8.0/playwright.ps1 install):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet tool install --global Microsoft.Playwright.CLI
playwright install --with-deps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eu fiz isso pelo simples motivo de não querer instalar o pwsh agora. Mas você deve fazer o recomendado, eu não. Faça o que eu não faço e seja melhor por nós dois.&lt;/p&gt;

&lt;h2&gt;
  
  
  Codegen
&lt;/h2&gt;

&lt;p&gt;Vamos logo para ferramenta. Eu estou com uma aplicação blazor (com blueprint) rodando localmente em &lt;a href="http://localhost:5000" rel="noopener noreferrer"&gt;http://localhost:5000&lt;/a&gt;.&lt;br&gt;
Para iniciar o comando mais simples é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;playwright codegen http://localhost:5000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso deve abrir duas janelas aí no seu pc:&lt;br&gt;
1 - Um navegador&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%2Fc1njl7xtkp7znffkhyr4.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%2Fc1njl7xtkp7znffkhyr4.png" alt=" " width="800" height="522"&gt;&lt;/a&gt;&lt;br&gt;
2 - Janela Inspeção / gravação&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%2F2jom8uvk5fgi2avqyr9a.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%2F2jom8uvk5fgi2avqyr9a.png" alt=" " width="607" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Já de início temos o código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Microsoft.Playwright;
using System;
using System.Threading.Tasks;

using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new()
{
    Headless = false,
});
var context = await browser.NewContextAsync();

var page = await context.NewPageAsync();
await page.GotoAsync("http://localhost:5000/");

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Que é o setup básico para início do teste. No seu teste de verdade quando for montar sua fixture, o Headless poderia ser false que evitaria que uma janela de navegador fosse "aberta visualmente".&lt;/p&gt;

&lt;p&gt;Repare que ele já inicia com a gravação ligada&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%2F6qkhriw8krdb33guz2b0.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%2F6qkhriw8krdb33guz2b0.png" alt=" " width="147" height="110"&gt;&lt;/a&gt;&lt;br&gt;
Então caso não queira testar algo direto na página inicial, você pode parar a gravação, navegar normalmente até onde deseja testar e depois voltar a gravação.&lt;/p&gt;

&lt;p&gt;Uma observação antes de continuarmos, talvez você possa ter problemas com certificado, então faça isso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;

namespace PlaywrightTests;

public class MyProjectTestBase : PageTest
{
 public MyProjectTestBase()
    {
        Playwright.Selectors.SetTestIdAttribute("propriedade-test");
    }
    public override BrowserNewContextOptions ContextOptions()
    {
        return new BrowserNewContextOptions
        {
            IgnoreHTTPSErrors = true
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e no seu teste herança de MyProjectTestBase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace PlaywrightTests;

public class UnitTest1 : MyProjectTestBase
{
    [Fact]
    public void TestName()
    {
        // Given

        // When

        // Then
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  1, 2, 3 teste testando
&lt;/h2&gt;

&lt;p&gt;O nosso setup já foi dado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await page.GotoAsync("http://localhost:5000/");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;falta nosso assert e aqui entra o arsenal do codegen:&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%2Fxe9mzuei61bynqhc7mjy.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%2Fxe9mzuei61bynqhc7mjy.png" alt=" " width="364" height="40"&gt;&lt;/a&gt;&lt;br&gt;
Clicando em assert visibility e passando o mouse por cima da pagína ele mostra como ele vai obter o elemento:&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%2Fmc4ez1qxjen9vr59rfoi.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%2Fmc4ez1qxjen9vr59rfoi.png" alt=" " width="800" height="263"&gt;&lt;/a&gt;&lt;br&gt;
e depois de clicar no elemento, já é feito o assert no gerador de código:&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%2Fcj439ii9gukjzjh5zvl8.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%2Fcj439ii9gukjzjh5zvl8.png" alt=" " width="800" height="263"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await Expect(page.GetByRole(AriaRole.Heading, new() { Name = "Welcome to BlazorBlueprint" })).ToBeVisibleAsync();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O assert text geraria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await Expect(page.Locator("h1")).ToContainTextAsync("Welcome to BlazorBlueprint");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o assert snapshot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await Expect(page.Locator("h1")).ToMatchAriaSnapshotAsync("- heading \"Welcome to BlazorBlueprint\" [level=1]");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E cabe a você decidir quais dessas segue mais o padrão de assert você quer fazer no seu código.&lt;br&gt;
Aqui foquei mais na parte do assert, mas vou mostrar também um pouco mais sobre outros aspectos de captura.&lt;/p&gt;

&lt;p&gt;Por exemplo num formulário, eu apenas clico em gravar, preencho normalmente e ele gera código:&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%2Fs6qtv6bi8z1na0b04y44.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%2Fs6qtv6bi8z1na0b04y44.png" alt=" " width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E grava também ao pressionar teclar e combinações:&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%2Flsvwv7114f05izo946gp.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%2Flsvwv7114f05izo946gp.png" alt=" " width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Options
&lt;/h2&gt;

&lt;p&gt;Essa parte aqui é bem importante para você executar o codegen com um contexto similiar ao que você teria na sobreescrita do MyProjectTestBase. Por exemplo, se no BrowserNewContextOptions você tem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return new BrowserNewContextOptions
        {
            IgnoreHTTPSErrors = true,
Locale = "en-US",
        };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;no codegen você deve iniciar ele com&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;playwright codegen --ignore-https-errors --lang "en-US" http://localhost:5000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E assim para todas as opções (incluindo --test-id-attribute que acho bem interessante no playwright que é definido no Playwright.Selectors.SetTestIdAttribute("propriedade-test"); por exemplo) que você pode encontrar no BrowserNewContextOptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Espero que você tenha aprendido alguma coisa que te ajude no seu fluxo de trabalho com codegen. No mais, qualquer dúvida, leia a documentação, converse com o chatgpt, pergunte ao seu líder de equipe, o seu açogueiro de confiança... Se nenhum deles te ajudar, manda uma mensagem lá no meu &lt;a href="https://www.linkedin.com/in/inacio88/" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>playwright</category>
      <category>testing</category>
    </item>
    <item>
      <title>Quem vigia os vigilantes: uma introdução a testes de mutação</title>
      <dc:creator>Inácio Bueno</dc:creator>
      <pubDate>Thu, 26 Jun 2025 00:54:49 +0000</pubDate>
      <link>https://forem.com/inacio88/quem-vigia-os-vigilantes-uma-introducao-a-testes-de-mutacao-1gp8</link>
      <guid>https://forem.com/inacio88/quem-vigia-os-vigilantes-uma-introducao-a-testes-de-mutacao-1gp8</guid>
      <description>&lt;p&gt;Testes de mutação podem dar ótimos indicadores de como / se os seus testes estão realmente preservando o estado de comportamento original da sua regra de negócio. Neste breve texto irei introduzir conceitualmente o que são testes de mutação e apresentar uma ferramenta para fazer esse tipo de análise.&lt;br&gt;
A ideia é bem simples: mutações são alterações no seu código, e se essas alterações no seu código não reprovarem no seu teste, pode ser que o seu teste seja ruim ou incompleto. Um exemplo rápido, imagine uma função que verifica se alguém é maior de 18 anos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public class Verificador
    {
        public bool EhMaiorDeIdade(int idade)
        {
            return idade &amp;gt;= 18;
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E que para o teste dessa função você tenha um único teste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        [Fact]
        public void Deve_Retornar_Verdadeiro_Para_Uma_Idade_Maior_Ou_Igual_18()
        {
            var verificador = new Verificador();

            var resultado = verificador.EhMaiorDeIdade(19);

            Assert.True(resultado);
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No primeiro olhar, tudo parece ok, a função é para verificar se é maior de idade, 19 anos seria alguém maior de idade o teste passou, então está tudo certo, certo?! É claro que esse é um exemplo simples e fácil de verificar que não, mas uma modificação (mutação) de "return idade &amp;gt;= 18;" para "return idade &amp;gt; 18;" continuaria fazendo com que o seu teste fosse aprovado, porém essa modificação quebrou a sua regra de negócio mas seu teste - que deveria ser aquilo que te alerta que alterações recentes alteraram crucialmente o comportamento inicialmente definido pela sua regra de negócio - não te diz nada.&lt;br&gt;
Aqui entra o &lt;a href="https://stryker-mutator.io/" rel="noopener noreferrer"&gt;Stryker&lt;/a&gt;, uma ferramenta que irá fazer essas mutações no seu código, e para cada mutação que for possível fazer, ela irá executar o teste. Se o seu teste passar com uma mutação (alteração), seu teste está incompleto; Se as mutações fizerem o seu teste reprovar elas, você está no caminho correto; digo "no caminho correto" porque as mutações feitas pela ferramenta tem sua limitações e que mutações/alterações feitas ao decorrer do tempo por programadores reais, têm bem mais sutilezas.&lt;br&gt;
Eu criei aqui dois projetos bem simples, um projeto console e outro é um projeto de testes. Caso queira fazer o mesmo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new console -n console.mutation; dotnet new sln -n solucao; dotnet new xunit -n teste.mutation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A ferramenta você pode instalar com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet tool install -g dotnet-stryker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entre no diretório do projeto de teste e rode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet-stryker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No caso do nosso exemplo, teríamos o seguinte resultado pelo terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100.00% │ Testing mutant 2 / 2 │ K 1 │ S 1 │ T 0 │ ~0m 00s │                                                       00:00:02                                                                                                                           
Killed:   1
Survived: 1
Timeout:  0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas também tem uma página html disponibilizada para ver com mais detalhes:&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%2Ftne9yr7nehn90dmc11qm.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%2Ftne9yr7nehn90dmc11qm.png" alt="Image description" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O diff em verde no código é a mutação feita pela ferramenta, e como indica no filtro ela foi a mutação que sobreviveu. Como Podemos matar ela? Simples, testando melhor: Se a função verifica se um número é maior ou igual 18, é fácil de ver que nosso teste testa apenas se maior e não se é maior ou igual. Ao teste vamos adicionar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Fact]
        public void Deve_Retornar_Verdadeiro_Para_Uma_Idade_Igual_18()
        {
            var verificador = new Verificador();

            var resultado = verificador.EhMaiorDeIdade(18);

            Assert.True(resultado);
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O teste completo fica assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public class TesteVerificador
    {
        [Fact]
        public void Deve_Retornar_Verdadeiro_Para_Uma_Idade_Maior_Ou_Igual_18()
        {
            var verificador = new Verificador();

            var resultado = verificador.EhMaiorDeIdade(19);

            Assert.True(resultado);
        }

        [Fact]
        public void Deve_Retornar_Verdadeiro_Para_Uma_Idade_Igual_18()
        {
            var verificador = new Verificador();

            var resultado = verificador.EhMaiorDeIdade(18);

            Assert.True(resultado);
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E rodando novamente a ferramenta temos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100.00% │ Testing mutant 2 / 2 │ K 2 │ S 0 │ T 0 │ ~0m 00s │                                                       00:00:02                                                                                                                           
Killed:   2
Survived: 0
Timeout:  0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E na parte gráfica:&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%2Ftrj8h4v78dcntbqulnk6.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%2Ftrj8h4v78dcntbqulnk6.png" alt="Image description" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Conseguimos matar a mutação e assim produzindo um teste mais significante.&lt;br&gt;
Espero que tenha gostado do texto e que tenha aprendido algo novo. Qualquer dúvida, leia a documentação. Até o próximo texto.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>dotnet counters tool</title>
      <dc:creator>Inácio Bueno</dc:creator>
      <pubDate>Fri, 28 Mar 2025 17:09:18 +0000</pubDate>
      <link>https://forem.com/inacio88/dotnet-counters-tool-44j8</link>
      <guid>https://forem.com/inacio88/dotnet-counters-tool-44j8</guid>
      <description>&lt;p&gt;A ferramenta dotnet-counters tem como objetivo monitorar a saúde de aplicações no .net. Majoritariamente utilizada para consumir valores disponibilizados pela eventCounter api, que, por sua vez,fornece valores como uso de cpu, número de exceções, e informações do uso de memória.&lt;br&gt;
Você pode instalar essa ferramenta com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet tool &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt; dotnet-counters
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Uso básico
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Lista os processos que podem ser monitorados
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet-counters ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;aqui tive o retorno (eu criei uma console application com o nome de gc e deixei sendo executada):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;350686  dotnet                     /usr/lib/dotnet/dotnet     dotnet gc.dll
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa primeira coluna nos fornece o id do processo: 350686. Com esse id podemos seguir para o próximo passo:&lt;/p&gt;

&lt;h4&gt;
  
  
  Monitor
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet-counters monitor -p 350686
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;temos com retorno:&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%2Ffyw2mq4o2fax7d2bua3a.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%2Ffyw2mq4o2fax7d2bua3a.png" alt="Image description" width="800" height="731"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Collect
&lt;/h4&gt;

&lt;p&gt;O collect monitora os contadores e exporta para um arquivo. Aqui nesse comando eu pedi para monitorar o mesmo processo anterior e pedi para o resultado ser exportado em json.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet-counters collect -p 350686 --format json -o dados.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;resultado:&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%2Fatzxq000c80p5xa6vx1y.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%2Fatzxq000c80p5xa6vx1y.png" alt="Image description" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  UI
&lt;/h2&gt;

&lt;p&gt;E para finalizar eu gostaria de trazer uma ferramenta com uma forma de visualização mais amigável. E essa é a &lt;a href="https://github.com/kkokosa/dotnet-counters-ui" rel="noopener noreferrer"&gt;https://github.com/kkokosa/dotnet-counters-ui&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com essa ferramente temos basicamente as mesmas opções, mas agora podemos ver em gráficos:&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%2F3ema26u20t63zsf9sfs2.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%2F3ema26u20t63zsf9sfs2.png" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos reunir em um mesmo gráficos vários contadores:&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%2F1xc8icxc6e5ho1f86p1v.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%2F1xc8icxc6e5ho1f86p1v.png" alt="Image description" width="800" height="772"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mas, por questões de escala, eu recomendo colocar informações diferentes em gráficos diferentes:&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%2Fvd0rotd4udx0fcd34x6i.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%2Fvd0rotd4udx0fcd34x6i.png" alt="Image description" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>i18n e ASP.NET Core Web API</title>
      <dc:creator>Inácio Bueno</dc:creator>
      <pubDate>Thu, 28 Nov 2024 21:07:49 +0000</pubDate>
      <link>https://forem.com/inacio88/i18n-e-aspnet-core-web-api-21eg</link>
      <guid>https://forem.com/inacio88/i18n-e-aspnet-core-web-api-21eg</guid>
      <description>&lt;p&gt;i18n é uma abreviação para internacionalização, um processo que visa tornar um software adaptável a diferentes idiomas e culturas, sem a necessidade de grandes reestruturações. Em outras palavras, é preparar um software para ser utilizado em qualquer parte do mundo. A i18n envolve a separação do texto do código, a formatação de datas, números e moedas de acordo com cada cultura, e o suporte a diferentes conjuntos de caracteres. Ao internacionalizar um software, você amplia seu alcance, melhora a experiência do usuário e aumenta sua competitividade no mercado global.&lt;br&gt;
Neste post irei te ensinar como iniciar o processo de internacionalização em um projeto webapi .net 8. Tenho aqui um projeto recém iniciado que usarei como exemplo e deixarei o link do github caso queira conferir o &lt;a href="https://github.com/inacio88/artigoExemploI18n" rel="noopener noreferrer"&gt;código&lt;/a&gt;.&lt;br&gt;
A primeira coisa que devemos fazer é adicionar o serviço de localização na aplicaçã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="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddLocalization&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;span class="c1"&gt;//Declaramos um array de culturas suportadas&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;supportedCultures&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="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"en-US"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"pt-BR"&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="c1"&gt;// Especificamos as opções para o RequestLocalizationMiddleware&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;localizationOptions&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;RequestLocalizationOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetDefaultCulture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pt-BR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSupportedCultures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;supportedCultures&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSupportedUICultures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;supportedCultures&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;span class="c1"&gt;// Adiciona o RequestLocalizationMiddleware para definir automaticamente as &lt;/span&gt;
&lt;span class="c1"&gt;// informações de cultura para solicitações com base nas informações &lt;/span&gt;
&lt;span class="c1"&gt;//fornecidas pelo cliente.&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;UseRequestLocalization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localizationOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(**Um detalhe importante que é ressaltado na documentação é que: "O middleware de localização precisa ser configurado antes de qualquer middleware que possa verificar a cultura de solicitação (por exemplo, app.UseMvcWithDefaultRoute())." Então preste atenção na ordem que vc está configurando os componentes do middleware.)&lt;/p&gt;

&lt;p&gt;Agora iremos adicionar os recursos necessários para fazer as traduções. Irei criar um projeto classlib chamado Common, adicioná-lo na solução e referenciá-lo no projeto da api (estou usando dotnet cli, mas fique à vontade para utilizar uma ide se preferir):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new classlib &lt;span class="nt"&gt;-n&lt;/span&gt; Common
dotnet sln add Common/
dotnet add Api/Api.csproj reference Common/Common.csproj
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro do projeto Common criamos um diretório chamado "Resources" e nele criaremos dois arquivos de recurso. A estrutura fica assim: &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%2Ftehshodowok2csjq34kk.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%2Ftehshodowok2csjq34kk.png" alt="Image description" width="401" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos começar a criar nosso primeiro texto para ser traduzido:&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%2F0biju7rr6sj62gji5cvv.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%2F0biju7rr6sj62gji5cvv.png" alt="Image description" width="800" height="242"&gt;&lt;/a&gt;&lt;br&gt;
O item (1) é chave (2) e (3) são os valores que serão utilizados conforme o idioma requisitado.&lt;br&gt;
Mas antes clique em propriedades do recurso, adicione Public nesse campo (custom tool):&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%2Fralw4pk07qishayig0g0.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%2Fralw4pk07qishayig0g0.png" alt="Image description" width="800" height="231"&gt;&lt;/a&gt;&lt;br&gt;
E também altere a classe Resource para ter seu modificador de acesso para Public&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;class&lt;/span&gt; &lt;span class="nc"&gt;Resource&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na controller iremo injetar o IStringLocalizer que vem de Microsoft.Extensions.Localization. E o Resource é o que criamos então faça também o using de Common.Resources;&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;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Localization&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Common.Resources&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Api.Controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WeatherForecastController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&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;IStringLocalizer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_localizer&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;WeatherForecastController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IStringLocalizer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;localizer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_localizer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;localizer&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="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"GetWeatherForecast"&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;Get&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="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Sucesso na traducao: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_localizer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"msg_sucesso"&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;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O uso do _localizer fica assim: _localizer["chave"].&lt;br&gt;
Para testar nossa aplicação utilizaremos o postman:&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%2Fui0yptd8orhinz2xozzi.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%2Fui0yptd8orhinz2xozzi.png" alt="Image description" width="769" height="497"&gt;&lt;/a&gt;&lt;br&gt;
E em inglês temos:&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%2Fzakf6ts5zc3pxvuk1j9c.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%2Fzakf6ts5zc3pxvuk1j9c.png" alt="Image description" width="738" height="501"&gt;&lt;/a&gt;&lt;br&gt;
E quando não colocamos nada, permanece aquele que configuramos como padrão:&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%2Fwuji9e7nbzqukpcb0n49.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%2Fwuji9e7nbzqukpcb0n49.png" alt="Image description" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E isso é tudo, pessoal! Fiquem à vontade para comentar qualquer equívoco ou sugestão. Espero que tenha te ajudado!&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>What is a chicken? An introduction to distroless containers</title>
      <dc:creator>Inácio Bueno</dc:creator>
      <pubDate>Wed, 30 Oct 2024 06:57:55 +0000</pubDate>
      <link>https://forem.com/inacio88/what-is-a-chicken-an-introduction-to-distroless-containers-215e</link>
      <guid>https://forem.com/inacio88/what-is-a-chicken-an-introduction-to-distroless-containers-215e</guid>
      <description>&lt;p&gt;I’d like to begin this article with a well known story amongst philosophers students, it goes something like: “&lt;em&gt;When Plato gave Socrates' definition of man as "featherless bipeds" and was much praised for the definition, Diogenes plucked a chicken and brought it into Plato's Academy, saying, "Behold! I've brought you a man."&lt;/em&gt;”&lt;/p&gt;

&lt;p&gt;Asking google what is a container, we get the following definition coming from docker (&lt;a href="https://www.docker.com/resources/what-container/):" rel="noopener noreferrer"&gt;https://www.docker.com/resources/what-container/):&lt;/a&gt; “&lt;em&gt;A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings&lt;/em&gt;”. I don’t think it’s a bad definition, but we know that there are a lot of chickens in it.&lt;/p&gt;

&lt;p&gt;And now the big question from this article:  What is needed to run an application? Let’s go to the terminal:&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%2F8lsc4qvcjissdj3a94be.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%2F8lsc4qvcjissdj3a94be.png" alt="Image description" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, I ran a container, specifically the aspnet runtime 8, listed some directories inside, used a command to write from 1 to 10, and then check the size of etc/; if you’re following along, you already know what I’m about to ask you: Why can I do all of those things? And you might say “I don’t know I have ADHD, I was already on instagram/tiktok sending videos to my friends; I got lost in the story of the guy who took a chicken to do who knows what ”. Fair point, I could say, but focus! And about the answer, in fact, I don’t know, maybe the ms team was just lazy and don’t really care for what they left there as long as your application runs it’s all fine. And if you’re so worried, do something yourself!&lt;br&gt;
Bash once again:&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%2F59d1ec3ioppxm5h7pmws.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%2F59d1ec3ioppxm5h7pmws.png" alt="Image description" width="800" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, we know where the binary of ls is, so just remove it, test if the application can still run without it and then add a line in our Dockerfile like RUN rm bin/ls. All done! Now you just need to remove all the other useless stuff. Life is beautiful and simple, I don’t get why so many people complain about it. But wait…. What other useless stuff? Can you remove ‘/’? Then you copy your application there and see what works. Right? YES! That's just the thing to do, in fact, do not even test it, do it directly in production. Say to your manager “devops is just a fancy word for easy work, let me handle it”.&lt;/p&gt;

&lt;p&gt;Distroless is what we are looking for: a container image that contains only the necessary to run the application AND NOTHING BEYOND THAT. It’s a hard job to do this, google did it first to run Golang applications, and nowadays there are other options to choose from.&lt;br&gt;
Here, let’s try do the same we did with the aspnet runtime container, but now a distroless:&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%2Fvnhcb3oxmgckiba8epp6.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%2Fvnhcb3oxmgckiba8epp6.png" alt="Image description" width="800" height="60"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Did you notice something? We couldn’t even get into the container, and if you are wondering, maybe it is zsh, ash, or sh… But no, we do not have a terminal in this container. If you look into chainguard description for the image cgr.dev/chainguard/aspnet-runtime:latest, you won’t find a terminal listed in the packages, neither you’ll find ls, seq, du…&lt;/p&gt;

&lt;p&gt;“But why do all of this work? Our company is doing fine without it”. The main reason: Security. Each package opens a door and it’s not a door to a good place. Let’s see some basic security analysis from these images.&lt;br&gt;
I’ve created 3 versions of the same dockerfile change only the images:&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%2F1jyd0odelukkzjwc7vdj.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%2F1jyd0odelukkzjwc7vdj.png" alt="Image description" width="800" height="60"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1.0 is the default image, 3.0 slim version and the 2.0 it’s distroless. (The first noticeable thing is the size, quite smaller. A big image does not mean that it’s bad, as may have heard, the implicit connection is that if your image is big then it contains more packages and thus it may introduce more vulnerabilities. But it’s not always the case.)&lt;br&gt;
Security analysis results using two different tools to analyze them:&lt;br&gt;
Default:&lt;/p&gt;

&lt;p&gt;1.0: Total: 78 (UNKNOWN: 0, LOW: 60, MEDIUM: 16, HIGH: 1, CRITICAL: 1)&lt;br&gt;
1.0: 24 vulnerabilities found in 13 packages&lt;/p&gt;

&lt;p&gt;Slim:&lt;/p&gt;

&lt;p&gt;3.0: Total: 78 (UNKNOWN: 0, LOW: 60, MEDIUM: 16, HIGH: 1, CRITICAL: 1)&lt;br&gt;
3.0: Detected 13 vulnerable packages with a total of 24 vulnerabilities&lt;/p&gt;

&lt;p&gt;Distroless:&lt;/p&gt;

&lt;p&gt;2.0: Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)&lt;br&gt;
 2.0: No vulnerable packages detected&lt;/p&gt;

&lt;p&gt;I hope with article you have learned something new, if you have any question message me on linkedin: &lt;a href="https://www.linkedin.com/in/inacio88" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/inacio88&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>distroless</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
