Tworzenie szablonu projektu w Visual Studio

Tworzenie szablonu projektu w Visual Studio

Wstęp

Dzisiaj temat będzie całkiem ciekawy. Utworzymy szablon projektu w Visual Studio. Po co to komu? Załóżmy, że często rozpoczynasz projekt od tego samego albo podobnego kodu. To idealny moment, żeby zrobić z tego szablon.

Na przykład ja. Czasem chcę stworzyć aplikację konsolową, ale z całym dobrodziejstwem .NetCore. Jak to zrobić pisałem w tym artykule. Jednak ciągłe powtarzanie tych samych czynności strasznie mnie denerwuje. Więc postanowiłem zgłębić temat i utworzyć szablon. Teraz wystarczy, że tworząc nowy projekt, nie będę wybierał Console Application, tylko mój własny szablon, w którym już jest zaszyte wszystko.

Zapraszam w podróż 🙂

Rodzaje szablonów

Mamy dwa rodzaje szablonów. Szablon pliku (item template) – to może być np. plik xml, json, plik zasobów itd. To są wszystko „item templates”.

Szablon projektu – tym się zajmujemy w tym artykule. To szablon całego projektu. Np. Console Application, czy też WebApi. To są wszystko „project templates”.

Szablon Visual Studio vs szablon .NET

Zasadniczo szablon można zrobić na dwa zupełnie różne sposoby.

Szablon dla Visual Studio

Jest prostszy w zrobieniu, zwłaszcza jeśli chcesz zrobić go szybko i bez zbędnych dupereli (okienek). Jednak zadziała tylko na VisualStudio pod Windowsem. To jest, można powiedzieć, klasyczna wersja. W tym artykule właśnie nim się zajmiemy. Zakłada utworzenie pliku .vstemplate.

Szablon pod .NET (Core)

Nowszą możliwością jest zrobienie szablonu pod .NET(Core). Taki szablon jest uniwersalny. Możesz zaimportować go do Visual Studio na Windows i na MACu. Możesz zaimportować go również do innych IDE, które mają takie wsparcie (jeśli znasz jakąś listę, podziel się w komentarzu). Zakłada utworzenie odpowiedniego katalogu i pliku .json. Bardzo uławia też tworzenie Wizarda.

Z czego składa się szablon

Jak wspomniałem, w tym artykule zajmiemy się tworzeniem szablonu „po staremu”. Wkrótce napiszę jak się robi szablon dla .NET.

Szablon zasadniczo składa się z dwóch części:

  • plików projektów, kodu źródłowego, plików zasobów
  • metadanych, które są przechowywane w pliku *.vstemplate.

Potem to wszystko jest pakowane do pliku *.zip i jest umieszczone w odpowiednim folderze (Dokumenty\Visual Studio 2022\Templates\ProjectTemplates).

I teraz pierwsza uwaga. Inaczej tworzy się szablon zawierający jeden projekt, a inaczej szablon z wieloma.

Najprostsze podejście

Szablon można bardzo łatwo i szybko utworzyć, wykorzystując funkcję Export Template w Visual Studio. Po prostu:

  • utwórz nowy projekt – bazę dla Twojego szablonu
  • zrób wymagane zmiany (dodaj, usuń, zmodyfikuj kod i pliki)
  • z menu głównego wybierz Project -> Export template

Przez resztę kroków przeprowadzi Cię zmyślny Wizard. Będziesz mógł dodać ikonkę do swojego szablonu, opis itd.

I to w zasadzie tyle. Ta metoda zapisze Twój szablon w odpowiednim miejscu, automatycznie go zaimportuje (jeśli nie odznaczyłeś tej opcji) i będziesz mógł korzystać z niego, tworząc nowy projekt. To jest najszybsza i najprostsza metoda.

Po takim utworzeniu szablonu, w katalogu z szablonami (Documenty\Visual Studio 2022\Templates\ProjectTemplates) zobaczysz plik *.zip o nazwie swojego szablonu. W środku znajdziesz wszystkie pliki, które dodałeś do niego, ale również kilka innych – dodanych przez Wizarda. Między innymi plik *.vstemplate, który w moim przypadku wygląda tak:

<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Project">
  <TemplateData>
    <Name>ConsoleWithNetCore</Name>
    <Description>Creates new console application with all .NetCore functionality like appSettings, dependency injection and so on.</Description>
    <ProjectType>CSharp</ProjectType>
    <ProjectSubType>
    </ProjectSubType>
    <SortOrder>1000</SortOrder>
    <CreateNewFolder>true</CreateNewFolder>
    <DefaultName>ConsoleWithNetCore</DefaultName>
    <ProvideDefaultName>true</ProvideDefaultName>
    <LocationField>Enabled</LocationField>
    <EnableLocationBrowseButton>true</EnableLocationBrowseButton>
    <CreateInPlace>true</CreateInPlace>
    <Icon>__TemplateIcon.ico</Icon>
  </TemplateData>
  <TemplateContent>
    <Project TargetFileName="ConsoleWithNetCoreTemplate.csproj" File="ConsoleWithNetCoreTemplate.csproj" ReplaceParameters="true">
      <Folder Name="Properties" TargetFolderName="Properties">
        <ProjectItem ReplaceParameters="true" TargetFileName="launchSettings.json">launchSettings.json</ProjectItem>
      </Folder>
      <ProjectItem ReplaceParameters="true" TargetFileName="Application.cs">Application.cs</ProjectItem>
      <ProjectItem ReplaceParameters="true" TargetFileName="appSettings.Development.json">appSettings.Development.json</ProjectItem>
      <ProjectItem ReplaceParameters="true" TargetFileName="appSettings.json">appSettings.json</ProjectItem>
      <ProjectItem ReplaceParameters="true" TargetFileName="Program.cs">Program.cs</ProjectItem>
      <ProjectItem ReplaceParameters="true" TargetFileName="Startup.cs">Startup.cs</ProjectItem>
    </Project>
  </TemplateContent>
</VSTemplate>

Zawartość tego pliku właściwie opisuje się sama.

I teraz uwaga. Jeśli podejrzysz sobie jakiś plik *.cs z tego szablonu, zobaczysz że zamiast konkretnej nazwy namespace’a masz coś takiego: $safeprojectname$, np:

using System;

namespace $safeprojectname$
{
    internal class MyClass
    {
    }
}

Wizard sprytnie podmienił nazwy Twoich namespace’ów na parametr $safeprojectname$. Dzięki temu, jeśli będziesz tworzył nowy projekt oparty o ten szablon, znajdzie się on w poprawnym namespace. I tu dochodzimy do tematu parametrów…

Parametry w szablonie

W swoim szablonie możesz mieć różne parametry. Parametry są otulone dolarami (jakby to nie brzmiało ;)), czyli tak: $nazwaParametru$. Wielkość liter MA znaczenie.

Jak się pewnie domyślasz po poprzednim akapicie, jest kilka parametrów predefiniowanych:

ParametrOpis
clrversionAktualna wersja common language runtime (CLR).
ext_*Prefix, który odnosi się do parametru w nadrzędnym szablonie (o tym później).
guid[1-10]GUID, który podmienia GUID projektu. Możesz używać 10 unikalnych takich identyfikatorów (np. guid1 – guid10).
itemnameNazwa aktualnego pliku (tego, w którym znajduje się parametr).
machinenameNazwa aktualnego komputera
projectnameNazwa projektu podana przez użytkownika podczas jego tworzenia. Dotyczy jedynie szablonów projektu.
registeredorganizationWartość z rejestru HKLM\Software\Microsoft\Windows NT\CurrentVersion\RegisteredOrganization wskazująca na zarejestrowaną organizację.
rootnamespaceGłówny namespace projektu. Po nim następuje nazwa podfolderu aktualnego elementu oddzielona kropką.
defaultnamespaceGłówny namespace aktualnego projektu.
safeitemnameTak samo jak itemname, jednak tutaj wszystkie niedopuszczalne znaki są zastępowane podkreślnikiem. Np zamiast: „moj projekt” będzie: „moj_projekt”.
safeitemrootnameTak samo jak itemname.
safeprojectnameNazwa projektu podana przez użytkownika podczas tworzenia projektu. Z tą różnicą, że wszystkie niedopuszczalne znaki są zastąpione podkreślnikiem. Tylko dla szablonów projektów.
targetframeworkversionAktualna wersja .NET Framework.
timeAktualny czas w formacie ustawionym w ustawieniach systemu Windows.
specifiedsolutionnameNazwa solucji. Gdy, podczas tworzenia projektu, użytkownik zaznaczy opcję „Create solution Directory”, wartością tego parametru jest nazwa solucji. W innym wypadku ta wartość jest pusta.
userdomainAktualna domena użytkownika.
usernameAktualna nazwa użytkownika.
yearAktualny rok w formacie YYYY.

A o tworzeniu własnych parametrów będzie później w tym artykule.

Jak działa ten mechanizm? Gdy będziesz tworzył projekt oparty na takiem szablonie, wszystkie parametry – wszystkie jego wystąpienia zostaną po prostu zamienione na odpowiednie wartości. Nie ważne, czy będą częścią stringa, czy kodu – WSZYSTKIE wystąpienia będą zastępione.

Szablon z wieloma projektami

Jak już mówiłem, szablon z kilkoma projektami robi się nieco inaczej. Stwórz sobie jakąś przykładową solucję. Ja utworzyłem solucję z dwoma projektami – jednym konsolowym i drugim class library:

Teraz dla każego projektu w tej solucji musisz wykonać eksport. Czyli tak jak wyżej. Z Menu Project wybierz Export template dla każdego projektu z osobna. Różnica będzie taka, że nie będziesz importować poszczególnych szablonów.

Pamiętaj, żeby odznaczyć opcję „Automatically import the template...”, bo w przeciwnym razie Visual Studio automatycznie zaimportuje utworzone templaty z poszczególnych projektów.

Gdy już wszystkie projekty zostały wyeksportowane jako poszczególne szablony, musisz utworzyć szablon nadrzędny, który będzie zawierał pozostałe.

To robisz ręcznie. Przejdź do katalogu, w którym utworzyły Ci się szablony. U mnie to: C:\Users\Admin\Documents\Visual Studio 2022\My Exported Templates\ (Wizard pokazuje Ci to w okienku Output Location, co widać na zrzucie wyżej).

Przejdź do tego katalogu. Zobaczysz w nim pliki zip swoich szablonów. Wypakuj je do ich katalogów:

Wypakowany katalog powinien zawierać bezpośrednio pliki szablonu. Bez żadnych dodatkowych zagnieżdżeń.

Teraz możesz już pozbyć się tych zipów i utworzyć plik XML z rozszerzeniem vstemplate:

Dorzuciłem tutaj też plik icon.ico – to jest ikonka, którą będzie posiadał szablon główny.

OK, to teraz pozostało uzupełnienie pliku vstemplate. Oto przykładowa zawartość:

<VSTemplate Version="2.0.0" Type="ProjectGroup"
    xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
    <TemplateData>
        <Name>Multi Project Template</Name>
        <Description>Przykład template'u z wieloma projektami</Description>
        <Icon>icon.ico</Icon>
        <ProjectType>CSharp</ProjectType>
    </TemplateData>
    <TemplateContent>
        <ProjectCollection>
            <ProjectTemplateLink ProjectName="Konsolka">
                MultiTemplateConsole\MyTemplate.vstemplate
            </ProjectTemplateLink>
            <ProjectTemplateLink ProjectName="Klaska">
                MultiTemplateClass\MyTemplate.vstemplate
            </ProjectTemplateLink>
        </ProjectCollection>
    </TemplateContent>
</VSTemplate>

Dane w pliku dość ładnie się same opisują.

  • TemplateData.Name – nazwa Twojego szablonu. Taka będzie widoczna w VisualStudio
  • TemplateData.Description – opis widoczny w VisualStudio
  • TemplateData.Icon – ikonka
  • TemplateData.ProjectType – typ projektu widoczny w VisualStudio. Ja wybrałem CSharp, ale oczywiście może to być dowolny język.

Następnie masz kolekcję szablonów poszczególnych projektów. Dodajesz po prostu te szablony wyeksportowane wcześniej.

ProjectName to będzie domyślna nazwa projektu w VisualStudio, gdy utworzysz go z tego szablonu:

Nowy projekt utworzony na podstawie szablonu

Teraz zawartość tego folderu potraktuj ZIPem:

Na końcu otrzymany plik ZIP skopiuj do katalogu z templateami projektów. U mnie to jest: C:\Users\Admin\Documents\Visual Studio 2022\Templates\ProjectTemplates.

Tworzenie szablonu z Wizardem

Tworzenie szablonu z Wizardem w ten sposób jest trudne. Nie opisuję tego specjalnie. Nigdy nie tworzyłem szablonu w taki sposób i nie potrzebuję tego robić, dlatego też nie opisuję tutaj tego. I tak byłaby to w większości zrzynka z dokumentacji Microsoftu: https://learn.microsoft.com/en-us/visualstudio/extensibility/how-to-use-wizards-with-project-templates?view=vs-2022

Jeśli jednak koniecznie MUSISZ zrobić w taki sposób szablon z Wizardem, musisz utworzyć projekt o typie Project Template (i kilka innych, ale ten jest podstawowy) i pamiętaj:

Visual Studio albo ma buga, albo zamierzoną funkcję. Nie możesz swojego projektu nazwać ProjectTemplate, ponieważ nie spodoba się to edytorowi.

Druga rzecz jaka może Cię zaskoczyć, to, że musisz używać pełnego frameworka, np. .NET Framework 4.7.2. Tak działa Visual Studio. W tym momencie będziesz tworzyć rozszerzenie dla VisualStudio, które pracuje pod Windowsem. Nie da się w taki sposób stworzyć szablonu (ani rozszerzenia) dla innego systemu. Dlatego, że VisualStudio korzysta z pełnej wersji Frameworka.

Jeśli nie tworzyłeś nigdy wcześniej żadnego rozszerzenia dla VS, dużo rzeczy może wydawać Ci się zawiłymi, części możesz nie zrozumieć. To kolejny powód, dla którego nie opisuję tego zagadnienia – za dużo wiedzy trzeba by było przekazać w jednym artykule. Ale na bank napiszę coś kiedyś o tworzeniu rozszerzeń (zwłaszcza w VS2022 jest to dużo przyjemniejsze niż w VS2015) i wtedy być może wrócę do tematu.

Szablon z Wizardem można zrobić dużo prościej za pomocą nowego podejścia do tworzenia szablonów (szablon dla .Net), o czym napiszę w kolejnym artykule.

Jeśli jednak będzie potrzeba, żeby napisać artykuł o szablonach z Wizardem dla Visual Studio, zrobię to jeśli będę miał wolniejszą chwilę – dajcie znać w komentarzu, czy chcecie coś takiego. Ale mniemam, że to jest na tyle zaawansowane zagadnienie, że ten kto naprawdę potrzebuje, to da sobie radę z załączoną dokumentacją Microsoftu: https://learn.microsoft.com/en-us/visualstudio/extensibility/how-to-use-wizards-with-project-templates?view=vs-2022


To tyle, dzięki za przeczytanie tego artykułu. Jeśli czegoś nie rozumiesz lub znalazłeś błąd, daj znać w komentarzu. I przygotuj się na kolejny z serii o szablonach – tym razem szablony .NET.

Obrazek artykułu: Obraz autorstwa vectorjuice na Freepik

Podziel się artykułem na: