Desenvolver aplicativos ASP.NET Core usando um inspetor de arquivos

Por Rick Anderson e Victor Hurdugaci

dotnet watch é uma ferramenta que executa um comando .NET CLI quando os arquivos de origem são alterados. Por exemplo, uma alteração de arquivo pode acionar compilação, execução de teste ou implantação.

Este tutorial usa uma API da Web existente com dois pontos de extremidade: um que retorna uma soma e outro que retorna um produto. O método do produto tem um bug, que é corrigido neste tutorial.

Transfira a aplicação de exemplo . Consiste em dois projetos: WebApp (uma API Web ASP.NET Core) e WebAppTests (testes de unidade para a API Web).

Em um shell de comando, navegue até a pasta WebApp . Execute o seguinte comando:

dotnet run

Note

Você pode usar dotnet run --project <PROJECT> para especificar um projeto a ser executado. Por exemplo, a execução dotnet run --project WebApp a partir da raiz do aplicativo de exemplo também executará o projeto WebApp .

A saída do console mostra mensagens semelhantes às seguintes (indicando que o aplicativo está em execução e aguardando solicitações):

$ dotnet run
Hosting environment: Development
Content root path: C:/Docs/aspnetcore/tutorials/dotnet-watch/sample/WebApp
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

Em um navegador da Web, navegue até http://localhost:<port number>/api/math/sum?a=4&b=5. Você irá ver o resultado de 9.

Navegue até a API do produto (http://localhost:<port number>/api/math/product?a=4&b=5). Ele retorna 9, não 20 como você esperaria. Esse problema é corrigido posteriormente no tutorial.

Adicionar dotnet watch a um projeto

A dotnet watch ferramenta inspetor de arquivos está incluída na versão 2.1.300 do SDK do .NET. As etapas a seguir são necessárias ao usar uma versão anterior do SDK do .NET.

  1. Adicione uma Microsoft.DotNet.Watcher.Tools referência de pacote ao .csproj arquivo:

    <ItemGroup>
        <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" />
    </ItemGroup>
    
  2. Instale o pacote Microsoft.DotNet.Watcher.Tools, executando o seguinte comando:

    dotnet restore
    

Executar comandos da CLI do .NET usando dotnet watch

Qualquer comando da CLI do .NET pode ser executado com dotnet watch. Por exemplo:

Command Comando com relógio
Dotnet Run Dotnet Watch Run
dotnet executar -f netcoreapp3.1 relógio dotnet executado -f netcoreapp3.1
dotnet run -f netcoreapp3.1 -- --arg1 (executar no ambiente .NET Core versão 3.1 com argumento arg1) relógio dotnet executado -f netcoreapp3.1 -- --arg1
teste dotnet teste de relógio dotnet

Execute dotnet watch run na pasta WebApp . A saída do console indica que watch foi iniciado.

A execução dotnet watch run em um aplicativo Web inicia um navegador que navega até a URL do aplicativo depois de pronto. dotnet watch faz isso lendo a saída do console do aplicativo e aguardando a mensagem pronta exibida pelo WebHost.

dotnet watch Atualiza o navegador quando ele deteta alterações em arquivos monitorados. Para fazer isso, o comando watch injeta um middleware no aplicativo que modifica as respostas HTML criadas pelo aplicativo. O middleware adiciona um bloco de script em JavaScript à página que permite ao dotnet watch instruir o navegador a refrescar. Atualmente, as alterações em todos os ficheiros vigiados, incluindo conteúdo estático, como ficheiros .html e .css, levam à reconstrução da aplicação.

dotnet watch:

  • Monitora apenas os arquivos que afetam as compilações por padrão.
  • Qualquer arquivo adicionalmente observado (via configuração) ainda resulta em uma compilação ocorrendo.

Para obter mais informações sobre configuração, consulte dotnet-watch configuration neste documento.

Note

Você pode usar dotnet watch --project <PROJECT> para especificar um projeto a ser observado. Por exemplo, executar dotnet watch --project WebApp run a partir da raiz da aplicação de exemplo também irá executar e monitorizar o projeto WebApp.

Faça alterações com dotnet watch

Certifique-se de que dotnet watch está em execução.

Corrija o bug no método Product de MathController.cs para que ele retorne o produto e não a soma.

public static int Product(int a, int b)
{
    return a * b;
}

Salve o arquivo. A saída do console indica que dotnet watch detetou uma alteração de arquivo e reiniciou o aplicativo.

Verify http://localhost:<port number>/api/math/product?a=4&b=5 retorna o resultado correto.

Execute testes usando dotnet watch

  1. Altere o método Product de MathController.cs para que volte a retornar a soma. Salve o arquivo.

  2. Em um shell de comando, navegue até a pasta WebAppTests .

  3. Execute dotnet restore.

  4. Execute dotnet watch test. Sua saída indica que um teste falhou e que o observador está aguardando alterações no arquivo.

    Total tests: 2. Passed: 1. Failed: 1. Skipped: 0.
    Test Run Failed.
    
  5. Corrija o código do Product método para que ele retorne o produto. Salve o arquivo.

dotnet watch deteta a alteração do arquivo e executa novamente os testes. A saída do console indica os testes aprovados.

Personalizar lista de arquivos para assistir

Por padrão, dotnet-watch rastreia todos os arquivos que correspondem aos seguintes padrões de glob:

  • **/*.cs
  • *.csproj
  • **/*.resx
  • Arquivos de conteúdo: wwwroot/**, **/*.config, **/*.json

Mais itens podem ser adicionados à lista de observação editando o .csproj arquivo. Os itens podem ser especificados individualmente ou através de padrões globais.

<ItemGroup>
    <!-- extends watching group to include *.js files -->
    <Watch Include="**\*.js" Exclude="node_modules\**\*;**\*.js.map;obj\**\*;bin\**\*" />
</ItemGroup>

Exclusão de arquivos a serem monitorizados

dotnet-watch pode ser configurado para ignorar suas configurações padrão. Para ignorar arquivos específicos, adicione o Watch="false" atributo à definição de um item no .csproj arquivo:

<ItemGroup>
    <!-- exclude Generated.cs from dotnet-watch -->
    <Compile Include="Generated.cs" Watch="false" />

    <!-- exclude Strings.resx from dotnet-watch -->
    <EmbeddedResource Include="Strings.resx" Watch="false" />

    <!-- exclude changes in this referenced project -->
    <ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj" Watch="false" />
</ItemGroup>
<ItemGroup>
     <!-- Exclude all Content items from being watched. -->
    <Content Update="@(Content)" Watch="false" />
</ItemGroup>

Projetos de relógios personalizados

dotnet-watch não se restringe a projetos C#. Projetos de relógios personalizados podem ser criados para lidar com diferentes cenários. Considere o seguinte layout de projeto:

  • test/
    • UnitTests/UnitTests.csproj
    • IntegrationTests/IntegrationTests.csproj

Se o objetivo for observar ambos os projetos, crie um arquivo de projeto personalizado configurado para observar ambos os projetos:

<Project>
    <ItemGroup>
        <TestProjects Include="**\*.csproj" />
        <Watch Include="**\*.cs" />
    </ItemGroup>

    <Target Name="Test">
        <MSBuild Targets="VSTest" Projects="@(TestProjects)" />
    </Target>

    <Import Project="$(MSBuildExtensionsPath)\Microsoft.Common.targets" />
</Project>

Para iniciar a observação de arquivos em ambos os projetos, mude para a pasta de teste . Execute o seguinte comando:

dotnet watch msbuild /t:Test

O VSTest é executado quando qualquer arquivo é alterado em qualquer projeto de teste.

Configuração do dotnet-watch

Algumas opções de configuração podem ser passadas para dotnet watch através de variáveis de ambiente. As variáveis disponíveis são:

Setting Description
DOTNET_USE_POLLING_FILE_WATCHER Se definido como "1" ou "true", dotnet watch usa um observador de arquivos de sondagem em vez do CoreFx's FileSystemWatcher. Usado ao assistir arquivos em compartilhamentos de rede ou volumes montados no Docker.
DOTNET_WATCH_SUPPRESS_MSBUILD_INCREMENTALISM Por padrão, o dotnet watch otimiza a compilação evitando certas operações, como executar a restauração ou reavaliar o conjunto de arquivos observados em cada alteração de arquivo. Se definido como "1" ou "true", essas otimizações serão desativadas.
DOTNET_WATCH_SUPPRESS_LAUNCH_BROWSER dotnet watch run tenta iniciar navegadores para aplicativos Web com launchBrowser configurado em launchSettings.json. Se definido como "1" ou "true", esse comportamento é suprimido.
DOTNET_WATCH_SUPPRESS_BROWSER_REFRESH dotnet watch run tenta atualizar os navegadores quando deteta alterações de ficheiros. Se definido como "1" ou "true", esse comportamento é suprimido. Esse comportamento também é suprimido se DOTNET_WATCH_SUPPRESS_LAUNCH_BROWSER estiver definido.

Atualização do navegador

dotnet watch Injeta um script no aplicativo que permite atualizar o navegador quando o conteúdo é alterado. Em alguns cenários, como quando o aplicativo habilita a compactação de resposta, dotnet watch talvez não seja possível injetar o script. Para esses casos em desenvolvimento, injete manualmente o script no aplicativo. Por exemplo, para configurar o aplicativo Web para injetar manualmente o script, atualize o arquivo de layout para incluir _framework/aspnet-browser-refresh.js:

@* _Layout.cshtml *@
<environment names="Development">
    <script src="/_framework/aspnetcore-browser-refresh.js"></script>
</environment>

Caracteres não-ASCII

Visual Studio 17.2 ou posterior inclui o .NET SDK 6.0.300 ou posterior. Com o SDK do .NET e 6.0.300 posterior, dotnet-watch emite caracteres não-ASCII para a consola durante uma sessão de hot reload. Em determinados hosts de console, como o conhost do Windows, esses caracteres podem parecer ilegíveis. Para evitar os caracteres ilegíveis, por favor considere uma das seguintes abordagens:

  • Configure a DOTNET_WATCH_SUPPRESS_EMOJIS=1 variável de ambiente para suprimir a emissão desses valores.
  • Mude para um terminal diferente, como https://github.com/microsoft/terminal, que suporte a renderização de caracteres não-ASCII.

Limites do observador de ficheiros no Linux

Ao correr dotnet watch em Linux ou em contentores Docker, pode encontrar um erro que indique que o limite de utilizador configurado para o número de instâncias inotify foi atingido:

The configured user limit (128) on the number of inotify instances has been reached, or the per-process limit on the number of open file descriptors has been reached.

Se o limite da instância inotify estiver esgotado, aumente fs.inotify.max_user_instances. Se o processo tiver atingido o limite do descritor de ficheiro aberto, aumente esse limite em vez disso. A definição separada fs.inotify.max_user_watches aplica-se quando o limite de relógio do inotify está esgotado.

Para aumentar temporariamente estes limites, execute os seguintes comandos:

sudo sysctl fs.inotify.max_user_instances=524288
sudo sysctl fs.inotify.max_user_watches=524288

Para tornar esta alteração permanente, adicione as seguintes linhas ao /etc/sysctl.conf ficheiro:

fs.inotify.max_user_instances=524288
fs.inotify.max_user_watches=524288

Note

Para contentores Docker, estes limites são herdados do sistema operativo anfitrião. Tem de configurar as definições de sysctl no computador anfitrião, em vez de no contentor.