Criando templates no Visual Studio

Criar templates no Visual Studio é a forma mais simples de parar de copiar e colar a mesma estrutura de arquivos a cada nova funcionalidade. Neste artigo, você vai montar um item template no Visual Studio 2019 que gera interface, request e implementação de um serviço de uma só vez.

O nosso dia a dia como dev é uma correria, pulando de um projeto para outro. Com isso, vêm as cópias de estruturas e de códigos existentes para criar algo novo.

Basicamente, copiamos o esqueleto de arquivos e depois renomeamos tudo para, só então, desenvolver o que realmente importa. Esse processo é natural, mas também muito repetitivo.

Por que criar templates no Visual Studio

Seria uma maravilha se, com um clique em New Item e a escolha de um arquivo, o Visual Studio 2019 criasse toda a estrutura para nós. Então comemore, pois esse dia chegou.

Os templates no Visual Studio fazem exatamente isso. Em outras palavras, você define uma vez o esqueleto dos arquivos e o IDE repete esse esqueleto sempre que precisar.

Assim, você melhora a produtividade do dia a dia e padroniza o código da equipe. Além disso, reduz erros bobos de renomeação, como uma classe que ficou com o nome do serviço antigo.

Item template e project template

A documentação da Microsoft separa os modelos em dois tipos. Os project templates aparecem na criação de um novo projeto, enquanto os item templates aparecem na janela Add New Item.

Neste tutorial, vamos trabalhar com um item template. Afinal, a ideia é adicionar novos arquivos a um projeto que já existe, e não criar um projeto do zero.

A documentação também explica que um item template representa um único item, mas esse item pode ter vários arquivos. É justamente esse recurso, chamado de item template com múltiplos arquivos, que vamos usar.

O que o nosso template vai gerar

Basicamente, vamos criar um template de serviço simples. A partir do Visual Studio 2019, ele vai gerar os seguintes arquivos:

  • Interface, onde fica declarada a assinatura do método.
  • Classe de request, que é o objeto enviado para esse serviço.
  • Classe de implementação, que implementa a interface e recebe o request como parâmetro.

É algo bem próximo do recurso de scaffold do ASP.NET Core MVC, que gera os controllers com as ações de forma automática. No entanto, aqui você controla cada linha do que será gerado.

Preparando o projeto para os templates no Visual Studio

Primeiro, crie um projeto do tipo Console Application. Esse tipo de projeto facilita a criação dos arquivos que envolvem a nossa automação de template.

Vou criar o projeto pelo Visual Studio 2019, porém nada impede de criá-lo pela .NET CLI. Se você ainda não tem o SDK instalado, veja o artigo sobre instalação e primeiros passos com .NET.

Tela inicial do Visual Studio 2019 com a opção de criar um novo projeto para o template
Ponto de partida: criar um novo projeto no Visual Studio 2019.
Lista de modelos de projeto do Visual Studio com a opção Console Application em destaque
Escolha do tipo Console Application para hospedar os arquivos do template.
Tela de configuração do nome e da pasta do projeto console no Visual Studio 2019
Definição do nome e do local do projeto.
Tela final de criação do projeto console com a escolha da versão do framework
Últimos ajustes antes de criar o projeto.

Depois que o projeto estiver criado, vamos montar a pasta que vai receber os arquivos do modelo.

Gerenciador de soluções do Visual Studio com o menu de contexto para adicionar uma nova pasta ao template
Adição de uma nova pasta pelo Solution Explorer.

Crie uma pasta chamada Template e, dentro dela, uma interface. No meu caso, comecei com o nome IRepository, mas você pode chamá-la como quiser.

Pasta Template criada no projeto console do Visual Studio com a interface inicial
A pasta Template organiza os arquivos que vão virar o modelo.
Janela Add New Item do Visual Studio com a opção Interface selecionada para o template
Criação da interface pela janela Add New Item.

No meu caso, vou montar a estrutura com o arquivo IServiceTemplate.cs, que é a interface do serviço. Ficou desta forma:

Solution Explorer exibindo o arquivo IServiceTemplate.cs dentro da pasta Template no Visual Studio
Estrutura do projeto com a interface criada.
Editor do Visual Studio mostrando a interface IServiceTemplate vazia
Conteúdo inicial da interface antes da exportação.

Exportando templates no Visual Studio

Logo após criar toda a estrutura, faça a exportação como template. Para isso, navegue até o menu Project > Export Template.

Menu Project do Visual Studio 2019 com a opção Export Template para gerar o template
O menu Project abre o assistente Export Template.

Segundo a documentação, se a opção não aparecer, você pode adicioná-la em Tools > Customize. Nesse caso, escolha a barra do menu Project e inclua o comando Export Template.

Escolhendo o tipo e o arquivo

Na primeira tela do assistente, selecione a opção Item Template. Em seguida, escolha o projeto que contém o arquivo e avance.

Assistente Export Template do Visual Studio com a opção Item Template selecionada
Item Template é o tipo certo para gerar arquivos dentro de projetos existentes.

Na próxima tela, selecione a interface que acabamos de criar. Ela será a base do modelo exportado.

Tela Select Item To Export com a interface IServiceTemplate marcada para o template no Visual Studio
Seleção da interface que será exportada.

Referências, nome e ícone

Caso queira, selecione algumas dependências nessa etapa. Com isso, o arquivo gerado pelo template já vem com essas importações, como o System.Linq.

Tela Select Item References do assistente com assemblies disponíveis para o template
Referências opcionais que acompanham o arquivo gerado.

Depois, preencha o nome do seu template e a descrição dele. Essa descrição aparece do lado direito da janela Add New Item quando alguém escolhe o modelo.

Também existe a possibilidade de colocar um ícone customizado. Eu não vou colocar, pois não é obrigatório, mas você pode usar o logo da empresa ou do projeto ao qual o template se destina.

Por fim, clique em Finish.

Tela Select Template Options com nome, descrição e opção de importação do template no Visual Studio
Nome, descrição e ícone do modelo antes de finalizar.

O arquivo zip gerado

O Visual Studio abre uma pasta com o template compactado em um arquivo zip. Segundo a documentação, o local padrão é a pasta My Exported Templates, dentro de Documents\Visual Studio 2019.

Copie esse arquivo para outro diretório, onde seja possível abri-lo no VS Code ou em outro editor de sua preferência.

Pasta do Windows Explorer exibindo o arquivo zip exportado pelo Visual Studio
O assistente entrega o modelo como um arquivo zip.

Extraia o conteúdo e abra a pasta no editor. Note que o assistente gerou três arquivos:

  • O ícone, que será exibido no Visual Studio 2019.
  • A classe de template, que neste caso é a interface.
  • O arquivo de configuração .vstemplate.
VS Code mostrando os três arquivos extraídos do template do Visual Studio
Conteúdo do zip: ícone, interface e arquivo vstemplate.

Editando o vstemplate para vários arquivos

Como o nosso template terá três arquivos de código, vamos editar manualmente o .vstemplate para aceitar os demais.

Esse arquivo é o que o Visual Studio lê para saber o que gerar. O arquivo padrão de configuração está desta forma:

Arquivo vstemplate padrão gerado pelo Visual Studio com um único ProjectItem
Configuração original, com apenas um arquivo.

Vamos editar para este modelo:

Arquivo vstemplate editado com três elementos ProjectItem para o template de serviço do Visual Studio
Configuração ajustada para gerar interface, request e implementação.

O código abaixo mostra uma versão equivalente, baseada no formato documentado pela Microsoft. Os nomes dos arquivos e as convenções podem variar conforme o padrão do seu projeto.

Vale notar que a documentação diz que o assistente gera os parâmetros sozinho quando o item já tem arquivos dependentes. Como os nossos templates no Visual Studio juntam arquivos independentes, a edição manual é necessária.

<VSTemplate Version="3.0.0" Type="Item"
    xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
  <TemplateData>
    <DefaultName>Service.cs</DefaultName>
    <Name>ServiceTemplate</Name>
    <Description>Creates the interface, request and implementation of a service</Description>
    <ProjectType>CSharp</ProjectType>
    <Icon>__TemplateIcon.ico</Icon>
  </TemplateData>
  <TemplateContent>
    <!-- Cada ProjectItem gera um arquivo no projeto -->
    <ProjectItem ReplaceParameters="true" TargetFileName="I$fileinputname$Service.cs">IServiceTemplate.cs</ProjectItem>
    <ProjectItem ReplaceParameters="true" TargetFileName="$fileinputname$Request.cs">ServiceTemplateRequest.cs</ProjectItem>
    <ProjectItem ReplaceParameters="true" TargetFileName="$fileinputname$Service.cs">ServiceTemplate.cs</ProjectItem>
  </TemplateContent>
</VSTemplate>

A variável fileinputname

Note que existe uma variável chamada $fileinputname$. Ela corresponde ao nome do arquivo digitado na criação do item pelo Visual Studio 2019, sem a extensão.

Por isso, você pode definir padrões de nomes com prefixo e sufixo, tudo de acordo com o padrão do seu projeto. A documentação confirma que, nesse cenário, os nomes dos arquivos derivam do nome informado na janela Add New Item.

Além disso, o atributo ReplaceParameters="true" habilita a troca de parâmetros dentro do conteúdo dos arquivos. Sem ele, os templates no Visual Studio copiam o texto exatamente como está, inclusive com os marcadores.

Outros parâmetros reservados também ajudam bastante. Por exemplo, o $rootnamespace$ traz o namespace raiz do projeto somado à subpasta onde o item foi criado.

Criando os arquivos do template no Visual Studio

Com o vstemplate pronto, falta escrever o conteúdo dos arquivos que o template do Visual Studio vai copiar.

Logo após ajustar a configuração no VS Code, crie os métodos padrões da sua interface. No meu caso, criei um método chamado Execute, que recebe um request criado pelo próprio template.

Interface IServiceTemplate com o método Execute recebendo o request no template do Visual Studio
A interface declara a assinatura do método Execute.
namespace $rootnamespace$
{
    // Contrato do serviço gerado pelo template
    public interface I$fileinputname$Service
    {
        void Execute($fileinputname$Request request);
    }
}

Em seguida, crie um arquivo chamado ServiceTemplateRequest.cs, ou com o nome que você desejar. Dentro dele, coloque o código da classe de request.

Classe ServiceTemplateRequest criada no editor para servir de parâmetro do serviço
A classe de request carrega os dados enviados ao serviço.
namespace $rootnamespace$
{
    // Objeto enviado como parâmetro para o serviço
    public class $fileinputname$Request
    {
    }
}

Essa classe será passada como parâmetro para o nosso método e para a nossa interface. Assim, cada serviço novo já nasce com o seu próprio objeto de entrada.

Na sequência, crie um arquivo chamado ServiceTemplate.cs, também com o nome que preferir. Dentro dele, faça a implementação da interface, conforme o exemplo abaixo.

Classe ServiceTemplate implementando a interface e o método Execute no template do Visual Studio
A implementação concreta do serviço gerado.
using System;

namespace $rootnamespace$
{
    // Implementação padrão do serviço gerado pelo template
    public class $fileinputname$Service : I$fileinputname$Service
    {
        public void Execute($fileinputname$Request request)
        {
            throw new NotImplementedException();
        }
    }
}

Nesse caso, a classe implementa a interface junto com o método Execute que criamos anteriormente. Portanto, o desenvolvedor só precisa preencher a lógica de negócio.

Repare que os três arquivos usam os mesmos marcadores. Assim, quando o Visual Studio aplica o template, a interface, o request e a implementação ficam coerentes entre si.

Importando templates no Visual Studio

Depois de finalizar as configurações e as implementações, vamos importar o modelo dentro do Visual Studio 2019. Primeiramente, compacte esses arquivos em um zip, desta forma:

Seleção dos arquivos do template no Windows Explorer com o menu para compactar
Os arquivos do modelo são compactados juntos.
Menu Enviar para do Windows com a opção Pasta compactada para gerar o zip do template
Criação do zip pelo próprio Windows.

O seu arquivo zip deve conter somente os arquivos de template, conforme a imagem abaixo. Ou seja, nada de pastas extras na raiz do pacote.

Conteúdo do zip final com o vstemplate, o ícone e os três arquivos de código do template para o Visual Studio
O zip contém apenas os arquivos do modelo na raiz.

Encontrando a pasta de item templates

Agora, dentro do Visual Studio 2019, navegue até Tools > Options.

Menu Tools do Visual Studio 2019 com a opção Options em destaque
As opções do IDE mostram onde ficam os modelos do usuário.

Pesquise pela palavra Locations e entre no menu Projects and Solutions. Em seguida, copie o caminho presente no campo de localização dos item templates do usuário.

Tela Projects and Solutions Locations do Visual Studio com o caminho dos item templates do usuário
O campo de item templates indica a pasta de destino do zip.

De acordo com a documentação, o caminho padrão é %USERPROFILE%\Documents\Visual Studio 2019\Templates\ItemTemplates. Abra esse caminho pela janela Executar, com a tecla Windows + R.

Janela Executar do Windows com o caminho da pasta ItemTemplates colado
Atalho rápido para abrir a pasta de templates.

Copiando o zip para o Visual Studio

Caso já exista algum zip com o mesmo nome por causa da exportação anterior, exclua o arquivo existente. Depois, cole o zip que você acabou de gerar.

Pasta ItemTemplates com o novo zip do template de serviço colado
O novo zip substitui o arquivo da exportação anterior.

Se quiser manter os modelos organizados, mova o zip para a pasta Visual C# ou para a pasta da linguagem de sua preferência. Feito isso, feche o Visual Studio 2019, porque ele só carrega os modelos novos ao iniciar.

Testando o template no Visual Studio

Abra novamente o projeto console no Visual Studio.

Projeto console reaberto no Visual Studio 2019 após a importação do template
Ao reabrir o IDE, o modelo importado já está disponível.

Agora vamos testar o template. Crie uma nova pasta chamada TemplateTest, para que os arquivos gerados fiquem separados dentro dela.

Pasta TemplateTest criada no Solution Explorer para receber os arquivos do template no Visual Studio
Pasta de teste para os arquivos gerados.

Logo na sequência, vá até o menu Add > New Item.

Menu de contexto Add com a opção New Item no Solution Explorer do Visual Studio
O modelo aparece na mesma janela dos itens padrão.

Note que o template criado já aparece em primeiro lugar. Porém, caso ele não esteja ali, pesquise pelo nome na barra de pesquisa do lado direito.

Janela Add New Item exibindo o template de serviço personalizado no topo da lista do Visual Studio
O template personalizado aparece entre os itens disponíveis.

Selecione o template e coloque o nome que desejar. Por exemplo, vou criar um serviço de CEP.

Campo Name da janela Add New Item preenchido com o nome do serviço de CEP
Basta informar o nome base do serviço.

Note que não preciso colocar a extensão .cs nem o prefixo ou o sufixo do serviço. Afinal, o $fileinputname$ e as regras do vstemplate cuidam disso.

Nome digitado sem extensão nem sufixo na criação do item a partir do template
O nome digitado alimenta a variável fileinputname.

Pronto, a estrutura padrão de um serviço foi criada com sucesso. Agora basta implementar a sua lógica, sem se preocupar em copiar arquivos e estruturas de outros lugares.

Solution Explorer exibindo os três arquivos gerados pelo template do Visual Studio na pasta TemplateTest
Os três arquivos do serviço gerados em um único passo.
Interface do serviço de CEP gerada automaticamente pelo template com o método Execute
A interface já nasce com a assinatura padrão.
Classe de implementação do serviço de CEP gerada pelo template do Visual Studio
A implementação gerada pronta para receber a lógica de negócio.

Boas práticas com templates no Visual Studio

Primeiro, mantenha os arquivos-fonte dos modelos em um repositório. Dessa forma, toda a equipe consegue revisar e evoluir os templates no Visual Studio como qualquer outro código.

Em seguida, prefira parâmetros reservados a nomes fixos. Por exemplo, usar $rootnamespace$ evita namespaces errados quando o item é criado em subpastas.

Também vale lembrar que os parâmetros diferenciam maiúsculas de minúsculas. Então, $FileInputName$ não funciona no lugar de $fileinputname$.

Por fim, se a equipe usa a linha de comando, conheça também o dotnet new e outras formas de geração de código. O artigo sobre T4 templates no .NET mostra uma alternativa para gerar código a partir de modelos de texto.

Compartilhando templates no Visual Studio com a equipe

O jeito mais simples de compartilhar é distribuir o próprio zip. Então, cada pessoa copia o arquivo para a sua pasta de item templates e reinicia o IDE.

Para equipes maiores, a documentação do Visual Studio SDK descreve outro caminho. Nesse caso, os templates no Visual Studio podem ser empacotados em uma extensão VSIX, o que facilita o versionamento e a instalação.

Desde o Visual Studio 2017, porém, o IDE não procura mais templates customizados dentro das extensões por conta própria. Por isso, a extensão precisa fornecer arquivos de manifesto que indiquem onde os modelos estão instalados.

Além disso, um template do Visual Studio pode instalar pacotes NuGet junto com os arquivos. Esse recurso ajuda quando o serviço gerado depende de bibliotecas específicas.

Conclusão

Espero que tenha gostado desta dica. Acredito que os templates vieram para agregar em nossas vidas, para focarmos no que realmente importa, que é gerar valor para o nosso cliente ou negócio.

Com poucos passos, você exportou um item template, editou o vstemplate para vários arquivos e importou o resultado no Visual Studio 2019. Para se aprofundar, consulte a documentação oficial sobre como criar item templates.

Até a próxima!

FAQ

Qual a diferença entre item template e project template?

O item template adiciona arquivos a um projeto existente pela janela Add New Item. Já o project template cria um projeto inteiro a partir do zero.

Onde o Visual Studio guarda os item templates do usuário?

Por padrão, na pasta Documents\Visual Studio 2019\Templates\ItemTemplates. Você confirma o caminho em Tools > Options > Projects and Solutions > Locations.

Para que serve o parâmetro fileinputname?

Ele recebe o nome digitado na janela Add New Item, sem a extensão. Assim, você monta os nomes dos arquivos com prefixos e sufixos padronizados.

Por que o template não aparece na janela Add New Item?

Normalmente, o Visual Studio ainda não foi reiniciado ou o zip está na pasta errada. Também confira se os arquivos estão na raiz do zip.

Preciso usar o assistente Export Template?

Não é obrigatório, porque você pode escrever o vstemplate à mão. Mesmo assim, o assistente gera a base e economiza tempo.