Julho de 2016

Volume 31 – Número 7

Essential .NET – Visual Studio 2015 com Ferramentas do .NET Core

De Mark Michaelis

Mark MichaelisO .NET Core RC2 finalmente chegou e desta vez é, na verdade, uma verdadeira versão “Release Candidate”, em vez de uma RC1 Beta disfarçada de release candidate (considerando todas as alterações que aconteceram após o lançamento). Muito do foco e da pressão no desenvolvimento em torno do .NET Core está certamente relacionado às capacidades entre plataformas. Este foco no suporte do Linux e do Mac OS X gerou não só uma nova API do .NET como também um tempo de execução de acompanhamento e até mesmo um conjunto de ferramentas. Ferramentas, como o DOTNET.EXE (anteriormente DNX, DNVM e DNU), para não mencionar o Visual Studio Code, servem para oferecer a desenvolvedores que não sejam da Microsoft uma oportunidade para aproveitar o .NET e, mais do que isso, uma experiência de primeira classe para desenvolvedores.

Isso é tudo muito bom, fantástico na verdade, mas e os desenvolvedores Microsoft mais antigos? Como eles continuam a desenvolver no Windows e no Visual Studio com projetos do .NET Core? Neste artigo, falarei sobre os vários tipos de projetos do .NET Core e explicarei os detalhes dos novos tipos de arquivos e suas funções. Também vou investigar como a nova estrutura de projeto suporta depurações lado a lado de qualquer pacote NuGet de código-fonte aberto que você possa mencionar e como você pode intervir no código-fonte de projetos deste tipo.

Introdução

Antes de poder começar a aproveitar o .NET Core RC2, você certamente desejará atualizar suas ferramentas, nesse caso o Visual Studio 2015, para dar suporte à nova plataforma. Isso essencialmente envolve duas etapas:

  1. Baixar o .NET Core Tooling Preview 1 para Visual Studio 2015 na página microsoft.com/net/core#windows (onde você também encontrará instruções).
  2. Instalar o Gerenciador do Pacote NuGet na página bit.ly/27Rmeaj.

Pressuponho que você tenha o Visual Studio 2015 já instalado, mas se não tiver, o Visual Studio Community Edition está disponível gratuitamente em visualstudio.com.

Novos Tipos de Projetos

Quando todas as ferramentas do Visual Studio estiverem instaladas, você pode usar o assistente de novos projetos para criar seu projeto (veja a Figura 1).

Modelos de Projetos do Visual Studio .NET Core
Figura 1 Modelos de projeto do Visual Studio .NET Core

Como você pode ver, há quatro tipos de projeto (um aparece duas vezes, pois reside tanto na pasta do Visual C#\Web quanto na do Visual C#\.NET Core).

Obviamente, cada tipo de projeto gera um conjunto diferente de arquivos, como mostrado na Figura 2.

Figura 2 Os Arquivos Incluídos em Cada Tipo de Projeto do Visual Studio

Nome do Arquivo Biblioteca de Classes Aplicativo de console Aplicativo Web ASP.NET Core (.NET Core) Aplicativo Web ASP.NET Core (.NET Framework)
App.config       X
Propriedades\AssemblyInfo.cs X X    
Class1.cs X      
Global.json X X X X
Properties\launchSettings.json     X X
Program.cs   X X X
Project.json X X X X
Project.lock.json X X X X
Project_Readme.html     X X
<Project>.xproj     X X
<Project>.xproj.user     X X
Startup.cs     X X
Web.config     X X

O App.config é um arquivo de configuração opcional semelhante ao tradicional <appname>.config usado desde o .NET Framework 1.0. O código a seguir mostra o arquivo padrão, que identifica quando usar a coleta de lixo baseada em servidor ou a coleta de lixo client/workstation-type (consulte bit.ly/22nm32o para obter mais informações):

<configuration>
  <runtime>
    <gcServer enabled="true"/>
   </runtime>
</configuration>

O AssemblyInfo.cs identifica os dados de assembly, como configuração, empresa, produto e marca registrada. Esse é o arquivo AssemblyInfo.cs padrão que faz parte dos projetos do Visual Studio .NET desde que o lançamento do .NET em 2000.

O Class1.cs é um arquivo de classe C# esqueleto para a classe Class1 e inclui seu construtor padrão.

O Global.json é gerado automaticamente contanto que você escolha “Criar um diretório para sua solução” ao criar seu primeiro projeto .NET Core. Conforme detalhado mais adiante no artigo, o nó do projeto identifica locais adicionais para o código-fonte durante a depuração.

LaunchSettings.json identifica as várias definições de configuração de hospedagem da Web, incluindo uma URL de aplicativo para depuração, um host IIS (como o IIS Express), se houver, variáveis de ambiente para definir antes do lançamento, usadas, por exemplo, pela configuração do .NET Core para identificar o ambiente (desenvolvimento, teste ou produção) e SSL e autenticação. As alterações feitas na guia Depurar na Janela de Propriedades do Projeto do Visual Studio fornecem uma interface do usuário para editar o arquivo launchSettings.json, como mostrado na Figura 3.

Guia Depurar na Janela de Propriedades do Projeto do Visual Studio
Figura 3 Guia Depurar na janela de propriedades do projeto do Visual Studio

A Figura 4 mostra um arquivo de amostra launchSettings.json.

Figura 4 Aquivo launchSettings.json de Exemplo

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:43799/",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "WebApplication1NetFramework": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Project.json é um novo arquivo de projeto cuja funcionalidade se sobrepõe, em grande parte, à do arquivo *.*PROJ. Ele identifica coisas como referências do projeto, opções de build, como número de versão, e identifica a plataforma a ser compilada, seja ela .NET Core ou .NET Framework, por exemplo. Falarei mais sobre o assunto em breve.

Project.lock.json armazena uma lista dos arquivos (normalmente referências NuGet) necessárias para compilação. Ela inclui números de versão de pacote específicos, ao contrário do arquivo project.json que suporta curingas. Sem o project.lock.json, ocorrerá uma restauração completa de pacotes. O arquivo Project.lock.json inclui um gráfico de pacote juntamente com outros dados relacionados a pacotes que foram baixados localmente (restaurados). Geralmente, este arquivo não é verificado e, quando não existe, é recriado com a execução de uma restauração do pacote NuGet. Este arquivo é listado como filho do project.json dentro do Visual Studio.

ClassLibrary.xproj é o arquivo MSBuild que, pronto para usado, define o que acontecerá quando você compila o projeto. A última versão importa Microsoft.DotNet.targets que define tarefas de compilação que otimizam o novo comando DotNet.exe. Ao contrário dos arquivos de projeto MSBuild no passado, os arquivos xproj são surpreendentemente pequenos, pois a maior parte da informação migrou (no momento) para o project.json.

ClassLibrary.xproj.user substitui o arquivo Class­Library.xproj e fornece propriedades MSBuild adicionais como configurações específicas de depuração como portas. Geralmente, este arquivo não é verificado, pois é específico do usuário e não é visível de dentro do Visual Studio.

Program.cs define uma classe de programa que inclui a definição do ponto de entrada principal de seu aplicativo, mesmo para aplicativos Web.

Web.config fornece uma configuração mínima para o IIS, instruindo-o onde encontrar o processo do host da Web e definindo que todo o tráfego seja redirecionado para esse processo, conforme mostrado no código a seguir:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule"
        resourceType="Unspecified"/>
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%"    
      stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout"
      forwardWindowsAuthToken="false"/>
  </system.webServer>
</configuration>

Observe que web.config já não contém configurações de aplicativo que, por sua vez, migraram para os arquivos de configuração que são carregados pelo Microsoft.Extensions.Configuration, tal como eu destaquei em meu artigo de fevereiro de 2016, “Configuração no .NET Core” (bit.ly/1OoqmkJ).

Observe que, com todos os tipos de projeto .NET Core criados pelo Visual Studio, selecionar “Criar um diretório para sua opção de solução” ao criar um novo projeto coloca todo o código-fonte em um subdiretório src da solução. Além disso, espera-se que os projetos de teste sejam colocados em um diretório de teste ao lado do src (apesar disso não ocorrer por padrão no .NET Core Tooling Preview 1 para a versão do Visual Studio 2015). Outros diretórios possíveis a considerar seriam para coisas como builds e documentos. (Confesso que preferiria manter meus projetos de teste juntamente com o projeto de destino que está sendo testado, em vez de em uma árvore totalmente separada, mas isso não é o que a Microsoft selecionou para a estrutura de solução padrão e a experiência me diz para usar a solução padrão sempre que possível em vez de tentar lutar contra ela.)

Mais sobre o Project.json

É provável que o arquivo mais significante na nova estrutura de projeto do .NET Core seja o project.json. Este arquivo foi criado para:

  • Substitua o arquivo package.config do Gerenciador de Arquivos do NuGet que identifica as referência do NuGet para o projeto.
  • Especifique quais estruturas o projeto suporta e os detalhes de configuração para saber como compilar o projeto para a estrutura específica.
  • Identifique a plataforma de destino para aplicativos autônomos que contêm todas as dependências, incluindo os tempos de execução específicos da plataforma do .NET Core necessários para a plataforma correspondente. Ou, se o projeto é um aplicativo portátil, o arquivo project.json identifica quais estruturas o projeto espera que sejam instaladas na máquina de destino na qual o assembly executará.

Essas três tarefas estão espalhadas pelas quatro principais seções dentro do project.json (eu combino tempos de execução e suportes conforme a funcionalidade vai sobrepondo, dependendo do tipo de projeto):

Dependências: Esta seção lista todos os pacotes NuGet dos quais seu projeto depende, incluindo o número de versão das ditas dependências. Os números de versão podem ser especificados com curingas para que você possa permitir que a “versão mais recente” coincida com o curinga a ser baixado automaticamente pela restauração do Gerenciador de Pacotes do NuGet. Algumas citações vazias do número de versão dizem: “Use a última versão disponível”. Além disso, você pode adicionar referências por meio da janela do Gerenciador de Pacotes do NuGet do Visual Studio e também pode confiar na maneira como o Visual Studio carrega o IntelliSense assincronicamente com os pacotes disponíveis a partir de sua fonte ou feed do pacote configurado (veja a Figura 5). O IntelliSense funciona para o nome do pacote e para o número de versão.

O IntelliSense é Carregado de Forma Dinâmica com a Lista de Pacotes e Versões Disponíveis
Figura 5 IntelliSense é carregado de forma dinâmica com a lista de pacotes e versões disponíveis

Estruturas: Nesta seção, você identifica as estruturas em que seu projeto será executado, por exemplo, net45, netstandard1.5 ou net40. Além disso, você pode fornecer buildOptions, dependências, frameworkAssemblies e importações – específicas do aplicativo para a estrutura identificada. Por exemplo, para permitir um código não seguro para o ambiente de execução do .NET 45, você pode especificar no elemento de estruturas:

"net45": {"buildOptions": {"allowUnsafe": true}}

Tempos de execução/suportes: se o project.json usa tempos de execução ou suportes depende se o projeto está destinado a ser um aplicativo portátil ou autônomo. Para aplicativos autônomos, os tempos de execução identificam quais sistemas operacionais serão suportados e, portanto, quais bibliotecas formarão um pacote no aplicativo. Um aplicativo autônomo não tem dependências (pelo menos no caso do .NET) sobre nada pré-instalado no computador de destino.

Em contrapartida, a seção de suportes identifica para os aplicativos portáteis as dependências de tempo de execução que um aplicativo procurará ao inicializar – qualquer uma dessas opções será suficiente. A lista não é restritiva (você pode executar em outro lugar), mas um elemento de suportes fará com que o NuGet verifique se todas as dependências são cumpridas.

Enquanto o project.json é essencial no RC1 e no RC2, ironicamente, não muito tempo após o lançamento do RC2, as equipes do .NET Core e do ASP.NET determinaram que o project.json era, na verdade, redundante com o arquivo de projeto MSBuild já estabelecido que suporta muito mais funcionalidades, incluindo configuração dependências de build, destinos de build, bandeiras de compilação, configurações de propriedade de ambiente variável e de linha de comando, além de comandos de build. Em vez de reinventar tudo isso, em primeiro lugar a equipe analisou o que disparava a criação do arquivo project.json e percebeu que os arquivos *.*PROJ ficavam geralmente muito sobrecarregados, listando todos os arquivos de um projeto individualmente, por exemplo, em vez de usar padrões de glob (curingas). A sobrecarga é tão significante que, na verdade, os desenvolvedores raramente abrem a analisam o arquivo antes de executar um build, mesmo que o arquivo pudesse ter algum comando indesejado integrado nele. Em vez de criar um arquivo de build totalmente novo, a equipe decidiu corrigir a sobrecarga dentro dos arquivos *.*PROJ e até fornecer um recurso de linha de comando para editá-lo. A sintaxe JSON é a única coisa que o arquivo project.json tem e os arquivos *.*PROJ não. (Mas, afinal de contas, JSON é apenas um XML moderno, assim como o XML foi, no seu tempo, o arquivo simples e moderno ou o arquivo INI.) Para obter mais informações sobre a possível extinção do project.json, consulte o anúncio de Damian Edwards durante o Community Standup do ASP.NET no dia 10 de maio de 2016 e a publicação correspondente de Alexandre Mutel (bit.ly/1NJ9r31), juntamente com o resumo de Willem Meints neste blog (bit.ly/1sJc2An).

Depuração do Código-fonte do Pacote

Uma das funcionalidades que mais me deixa entusiasmado no momento é o novo suporte à depuração e a introdução aos pacotes que permite até modificar o código-fonte dos pacotes, caso esteja disponível. Imagine, por exemplo, que você tenha um assembly do “Framework” em toda a empresa e que ele seja compartilhado com várias equipes. No entanto, o pacote do Framework é essencialmente de código-fonte aberto, de forma que qualquer pessoa dentro da empresa (ou, ainda melhor, de fora da empresa) pode contribuir com melhorias e alterações. Agora, imagine que você faça referencia ao pacote do NuGet para esse Framework mas, em determinado momento, suspeite que possa existir um bug que precisa ser corrigido ou, talvez, a garantia de um aprimoramento. Normalmente, isso exige trabalhar com o código-fonte do componente independentemente de seu projeto ou solução. E se, em vez disso, você pudesse baixar o código-fonte e atualizá-lo como uma experiência integrada juntamente com seu desenvolvimento principal chegando a intervir no código sem confiar em um servidor de símbolo ou nos arquivos PDB disponibilizados? Felizmente, este é um cenário essencial no Visual Studio 2015.

Por exemplo, imagine que você queira depurar o pacote Microsoft.Extensions.Logging disponível no GitHub. Para adicioná-lo e depurá-lo dentro se seu projeto, baixe (usando o clone de Git ou o comando do submódulo de Git) o código-fonte. Em seguida, para que o Visual Studio saiba onde encontrar o código-fonte, você precisa editar o nó do projeto global.json adicionando, por exemplo, “submódulos\registro” à lista de diretórios que ele inspeciona:

{
  "projects": [ "src", "test", "submodules\Logging" ],
  "sdk": {
    "version": "1.0.0-*"
  }
}

Obviamente você também pode fornecer um caminho completo (se, por exemplo, você não tiver clonado o código em um subdiretório). No entanto, observe que o separador do diretório são duas barras invertidas (\\) ou uma única barra (por exemplo c:/users/mark/documents/visual studio2015/Projects/Microsoft.Extensions.Logging).

Após o Visual Studio encontrar o código-fonte depois do global.json ser atualizado e salvo, ele adicionará automaticamente o projeto à sua solução de forma que você possa então depurar no código-fonte.

Um algoritmo relativamente simples é usado para determinar qual diretório de código-fonte carregar:

  1. Se qualquer localização do código-fonte especificada no global.json contiver uma pasta com o mesmo nome do pacote (como Microsoft.Extensions.Logging) e essa pasta contiver um arquivo chamado project.json, o depurador usará essa pasta e os arquivos fonte dentro dela.
  2. Caso contrário, o binário compilado a partir da pasta de pacotes é carregado.

Para mais informações, consulte “Depuração do Código do ASP.NET 5 Framework Usando o Visual Studio 2015” (bit.ly/22niJ7w).

Conclusão

Se você ainda não começou a explorar o .NET Core mais aprofundadamente, agora é um ótimo momento para fazê-lo, pois você terá um período de tempo maior para amortizar a curva de aprendizagem. Isso também se aplica a quem estiver considerando atualizar a partir de versões anteriores. É bem provável que você passará pelo processo de atualização em algum momento e quanto mais cedo você o fizer, mais cedo você aproveitará as novas funcionalidades.


Mark Michaelis é fundador da IntelliTect, onde atua como arquiteto técnico principal e instrutor. Há quase 20 anos trabalha como Microsoft MVP, e é Diretor Regional da Microsoft desde 2007. Michaelis atua em diversas equipes de análise de design de software da Microsoft, incluindo C#, Microsoft Azure, SharePoint e Visual Studio ALM. Ele dá palestras em conferências de desenvolvedores e escreveu diversos livros, incluindo o mais recente, "Essential C# 6.0 (5th Edition)" (itl.tc/­EssentialCSharp). Você pode entrar em contato com ele pelo Facebook, em facebook.com/Mark.Michaelis, pelo seu blog IntelliTect.com/Mark, no Twitter: @markmichaelis ou pelo email mark@IntelliTect.com.

Agradecemos aos seguintes especialistas técnicos da IntelliTect pela revisão deste artigo: Kevin Bost, Andrew Scott e Michael Stokesbary