Snippet ve Live Template Yazmak: VS Code, Visual Studio ve Rider'da Kendi C# ve Angular Kısayolların
Snippet, dilin syntax'ı yüzünden her seferinde yazdığın küçük iskeletler için doğru araç; tekrar eden mantık için değil. Bookstore'un xUnit v3 testi, minimal API endpoint group'u, EF Core configuration'ı ve Angular 22 component'i için VS Code snippet'lerini, namespace'i dosya yolundan üreten transform'u, Visual Studio .snippet ve Rider live template karşılıklarını ve snippet dosyasını sessizce ignore eden .gitignore satırını gösteriyoruz.
Sürüm notu: Bu yazıdaki snippet dosyaları ve ürettikleri kod .NET 10 (SDK 10.0.404), xUnit v3 (xunit.v3.mtp-v2 4.0.3), Entity Framework Core 10.0.15, Angular 22.2 ve Node.js 24 ile derlenip denenmiştir. IDE tarafındaki davranışlar Visual Studio Code (VS Code), Visual Studio 2026 ve Rider 2026.3 belgelerine dayanır.
Önce Tahmin Et
Bookstore'da (sitedeki serilerin ortak örnek uygulaması, bir online kitapçı) Emre yeni bir test dosyası açıyor, bsfact yazıp Tab'a basıyor ve ekibin ortak test iskeleti geliyor. Snippet, repo'daki .vscode/bookstore.code-snippets dosyasında duruyor. Ayşe aynı repo'yu klonluyor, aynı klasörü VS Code'da açıyor, bsfact yazıyor ve listede hiçbir şey çıkmıyor.
Emre dosyayı commit ettiğini söylüyor, git log da commit'i gösteriyor. Ayşe'nin ayarlarında bir sorun yok. Snippet nerede kayboldu? İpucu: suçlu, repo'yu ilk gün oluşturan komutlardan biri. Cevap "Ekiple Paylaşmak" bölümünde.
Snippet Ne Zaman Doğru Araç?
Snippet, editörün kısa bir kelimeyi önceden yazılmış bir kalıba çevirmesi. En çok işe yaradığı yer, dilin ya da framework'ün syntax'ı yüzünden her seferinde yazmak zorunda olduğun küçük iskeletler: bir test method'u, minimal API endpoint group'u, Entity Framework Core (EF Core; .NET'in veritabanı erişim kütüphanesi) entity configuration'ı, bir Angular component'i. Hepsinde yapı aynı, değişen yalnız isimler. Bu yapıyı abstraction ile ortadan kaldıramazsın, çünkü tekrar eden şey mantık değil syntax.
Yanlış olduğu yer, aynı mantığı (validation, mapping, hata yakalama) snippet ile on dosyaya kopyalamak. On kopyaya yayılan kod, içindeki hatayı da on yere yayar. Pratik bir ölçüt: snippet'in ürettiği kodu sonradan her kopyada aynı şekilde değiştirmen gerekiyorsa, o kod snippet değil, helper method, base class ya da extension method olmalı.
Kendi snippet'ini yazmadan önce yerleşik olanlara bak. Visual Studio C# için prop, propfull, ctor, cw, foreach, try gibi otuzdan fazla snippet getirir; ctor, içinde bulunduğun class'ın adını ClassName() function'ı ile alır. Rider'da aynı adlarla live template'ler var. VS Code'da C# extension'ının snippets/csharp.json dosyası 42 snippet içeriyor; oradaki ctor class adını değil dosya adını ($TM_FILENAME_BASE) kullanıyor, hatta bir fact snippet'i de var. Angular framework'ü snippet getirmez; a-component gibi kısaltmalar John Papa'nın Angular Snippets extension'ından gelir.
Yerleşik fact işini görüyorsa kendininkini yazma. Bizim ekip kendi sürümünü yazdı, çünkü iki şey istiyordu: Method_Scenario_ExpectedResult isim kuralı ve [Fact] ile [Theory] arasında tek tuşla seçim.
VS Code: .code-snippets Dosyası
VS Code'da snippet'ler JSON dosyalarında durur. Üç yer var: tek bir dil için kullanıcı dosyası (ör. csharp.json), bütün dillerde geçerli global .code-snippets dosyası ve proje kökündeki .vscode klasöründe duran .code-snippets dosyaları. Ekip için doğru olan üçüncüsü, çünkü repo ile birlikte gelir. Bookstore'un dosyasındaki ilk snippet:
{
"xUnit v3 fact": {
"scope": "csharp",
"prefix": "bsfact",
"description": "Bookstore: xUnit v3 test named Method_Scenario_ExpectedResult",
"body": [
"[${1|Fact,Theory|}]",
"public ${2|void,async Task|} ${3:Method}_${4:Scenario}_${5:ExpectedResult}()",
"{",
" $0",
"}"
]
}
}
prefix tetikleyen kelime, body satır satır eklenecek metin, description IntelliSense'te görünen açıklama. scope snippet'i dillere bağlar; değer, VS Code'un language identifier'ı (csharp, typescript, html). Belgeye göre global dosyada scope vermezsen snippet bütün dillerde önerilir; YAML (girintiye dayalı configuration formatı) yazarken bsfact önerisi görmek istemezsin.
Body'deki işaretler: $1, $2 tab stop'lar, Tab ile sırayla dolaşılır; $0 son imleç konumu. ${3:Method} varsayılan metni olan bir placeholder, ${1|Fact,Theory|} ise listeden seçilen bir choice. Aynı numara iki yerde geçerse ikisi birlikte değişir. Snippet'ler IntelliSense listesinde diğer önerilerle karışık görünür; yalnız Tab ile açılmasını istiyorsan "editor.tabCompletion": "on" ayarı gerekir.
bsfact ile yazılmış bir test ve çalışması:
public sealed class InMemoryBookCatalogTests
{
[Fact]
public void FindByIsbn_UnknownIsbn_ReturnsNull()
{
InMemoryBookCatalog catalog = new();
Book? book = catalog.FindByIsbn("9780000000000");
Assert.Null(book);
}
}
$ dotnet test
Test run summary: Passed!
total: 2
failed: 0
succeeded: 2
skipped: 0
duration: 242ms
Dosyanın tamamını dolduran snippet'ler için "isFileTemplate": true var: boş bir dosyada Command Palette'ten "Snippets: Fill File with Snippet" çalıştırınca bu snippet'ler listelenir. include ve exclude glob'larıyla snippet'i belli dosyalara sınırlayabilirsin; ikisi çakışırsa exclude kazanır.
Bu bölümde resmî belgelerden yararlanılmıştır.
Variable ve Transform: Namespace'i Dosya Yolundan Üretmek
Asıl zaman kazandıran kısım variable'lar. TM_FILENAME_BASE uzantısız dosya adı, RELATIVE_FILEPATH workspace köküne göre dosya yolu, CURRENT_YEAR, UUID ve CLIPBOARD gibi değerler de var. Her variable'a ${VAR/regex/format/options} biçiminde bir transform uygulanabilir. Bookstore'un endpoint ve configuration snippet'leri namespace'i dosya yolundan üretiyor:
"namespace ${RELATIVE_FILEPATH/^\\w+\\W|\\W[\\w.]+$|(\\W)/${1:+.}/g};",
Regex'te üç alternatif var: baştaki src/ ya da tests/ parçası, sondaki /BookConfiguration.cs parçası ve aradaki her ayırıcı. İlk ikisi boşa, ayırıcı noktaya çevrilir; ${1:+.} "birinci grup eşleştiyse nokta yaz" demek. Ayırıcıyı / diye değil \W diye yazmamın sebebi Windows: orada RELATIVE_FILEPATH ters bölü ile gelir. İkinci sebep, transform'un parçalarının / ile ayrılması: regex'in içinde / geçerse kaçış karakteriyle yazmak gerekiyor, \W bu sorunu hiç doğurmuyor.
VS Code transform'ları JavaScript regex motoruyla çalıştırır. Bu yüzden regex'i snippet'e koymadan önce Node'da denemek mümkün:
// VS Code transform'ları JavaScript regex'iyle çalıştırır;
// aynı regex'i snippet'e koymadan önce Node'da deneyebiliriz.
const ns = (path) =>
path.replace(/^\w+\W|\W[\w.]+$|(\W)/g, (_match, sep) => (sep ? '.' : ''));
for (const path of [
'src/Bookstore.Api/BookEndpoints.cs',
'src\\Bookstore.Catalog\\Persistence\\BookConfiguration.cs',
'tests/Bookstore.Catalog.Tests/BookConfigurationTests.cs',
]) {
console.log(`${path} -> ${ns(path)}`);
}
console.log('BookConfiguration ->', 'BookConfiguration'.replace(/(.*)Configuration$/, '$1'));
$ node tools/snippets/check-transforms.mjs
src/Bookstore.Api/BookEndpoints.cs -> Bookstore.Api
src\Bookstore.Catalog\Persistence\BookConfiguration.cs -> Bookstore.Catalog.Persistence
tests/Bookstore.Catalog.Tests/BookConfigurationTests.cs -> Bookstore.Catalog.Tests
BookConfiguration -> Book
Format kısmında büyük-küçük harf dönüşümleri de var: /upcase, /downcase, /capitalize, /camelcase, /pascalcase, /kebabcase, /snakecase. Angular snippet'i class adını ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/} ile book-card dosya adından BookCard olarak üretiyor.
Bookstore Snippet'leri: Endpoint Group, EF Core ve Angular
Dosyada dört snippet var: bsfact, bsendpoints, bsconfig ve bscomponent. bsconfig, adı Configuration ile biten dosyadan entity adını çıkarıyor. Snippet'in body kısmı:
"body": [
"using Microsoft.EntityFrameworkCore;",
"using Microsoft.EntityFrameworkCore.Metadata.Builders;",
"",
"namespace ${RELATIVE_FILEPATH/^\\w+\\W|\\W[\\w.]+$|(\\W)/${1:+.}/g};",
"",
"internal sealed class ${TM_FILENAME_BASE} : IEntityTypeConfiguration<${1:${TM_FILENAME_BASE/(.*)Configuration$/$1/}}>",
"{",
" public void Configure(EntityTypeBuilder<${1}> builder)",
" {",
" builder.ToTable(\"${2:${1}s}\");",
" builder.HasKey(x => x.${3:Id});",
" $0",
" }",
"}"
]
src/Bookstore.Catalog/Persistence/BookConfiguration.cs dosyasında çağırıp Id yerine Isbn yazınca ve iki satır ekleyince ortaya çıkan dosya:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Bookstore.Catalog.Persistence;
internal sealed class BookConfiguration : IEntityTypeConfiguration<Book>
{
public void Configure(EntityTypeBuilder<Book> builder)
{
builder.ToTable("Books");
builder.HasKey(x => x.Isbn);
builder.Property(x => x.Isbn).HasMaxLength(13);
builder.Property(x => x.Price).HasPrecision(10, 2);
}
}
Angular snippet'ini yazmadan önce Angular 22 CLI'ın ne ürettiğine baktım, çünkü snippet CLI'dan farklı kod üretirse ekipte iki stil oluşur. ng generate component book-card çıktısı book-card.ts adında bir dosya ve BookCard adında bir class veriyor; .component son eki, standalone: true ve changeDetection satırı yok. Angular 22'nin ChangeDetectionStrategy tanımındaki açıklama OnPush'un artık varsayılan olduğunu yazıyor. Snippet bu yüzden yalnız gerekeni ekliyor; bscomponent'in body kısmı:
"body": [
"import { Component, input } from '@angular/core';",
"import { ${2:Book} } from '${3:../book}';",
"",
"@Component({",
" selector: 'app-${TM_FILENAME_BASE}',",
" templateUrl: './${TM_FILENAME_BASE}.html',",
" styleUrl: './${TM_FILENAME_BASE}.css',",
"})",
"export class ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/} {",
" readonly ${1:book} = input.required<${2}>();",
" $0",
"}"
]
Snippet'lerin ürettiği dosyalar repo'da gerçek kod olarak duruyor ve derleniyor. Böylece snippet bozulursa bunu ilk fark eden build oluyor:
$ dotnet build
0 Warning(s)
0 Error(s)
$ npx ng test --watch=false
Test Files 2 passed (2)
Tests 2 passed (2)
Visual Studio: .snippet XML'i
Visual Studio aynı fikri XML ile ifade ediyor. bsfact karşılığı:
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>xUnit v3 fact</Title>
<Shortcut>bsfact</Shortcut>
<Description>Bookstore: xUnit v3 test named Method_Scenario_ExpectedResult</Description>
<Author>Bookstore team</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Imports>
<Import>
<Namespace>Xunit</Namespace>
</Import>
</Imports>
<Declarations>
<Literal>
<ID>method</ID>
<ToolTip>Method under test</ToolTip>
<Default>Method</Default>
</Literal>
<Literal>
<ID>scenario</ID>
<ToolTip>Input or state</ToolTip>
<Default>Scenario</Default>
</Literal>
<Literal>
<ID>expected</ID>
<ToolTip>Expected result</ToolTip>
<Default>ExpectedResult</Default>
</Literal>
</Declarations>
<Code Language="CSharp" Kind="method decl">
<![CDATA[[Fact]
public void $method$_$scenario$_$expected$()
{
$end$
}]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
Literal düzenlenebilir bir alan: ID ile tanımlanır, kodda $method$ diye kullanılır, Default zorunlu. $end$ son imleç konumu, $selected$ seçili metin; ikisi de birer kez kullanılabilir. Kind="method decl" snippet'in yalnız bir class içinde, method tanımlanabilecek yerde önerilmesini sağlar. Imports eksikse dosyaya using Xunit; ekler. Bir kısıt yüzünden VS Code'daki adı da bsfact yaptım: Shortcut yalnız harf, rakam ve alt çizgi kabul ediyor, bs-fact olmuyor.
VS Code ile fark büyük: C# snippet'lerinde yalnız üç function var (ClassName(), SimpleTypeName(), GenerateSwitchCases()); dosya adından değer üretmek ya da regex ile dönüştürmek yok. Kurulum için Tools menüsünden Code Snippets Manager'ı açarsın (Ctrl+K, Ctrl+B); Import dosyayı %USERPROFILE%\Documents\Visual Studio 18\Code Snippets\Visual C#\My Code Snippets altına kopyalar. Ekip için daha iyisi aynı penceredeki Add düğmesi: repo'daki tools/snippets/visualstudio klasörünü snippet klasörü olarak ekler, git pull ile gelen değişiklik doğrudan görünür. C#'ta shortcut'ı yazıp iki kez Tab'a basınca snippet açılır; Ctrl+K, X listeden seçtirir. Daha geniş dağıtım için belge snippet'leri bir VSIX (Visual Studio için extension paketi) dosyasına koymayı anlatıyor.
Bu bölümde resmî belgelerden yararlanılmıştır.
Rider: Live Template ve Macro'lar
Rider'da karşılığı live template. Settings (Ctrl+Alt+S) altında Editor | Live Templates sayfasında oluşturulur; değişkenler $METHOD$ gibi dolar işaretleri arasında yazılır, $END$ son imleç konumu, $SELECTION$ seçili metin. Asıl gücü macro'lar: bir değişkenin değerini Rider hesaplar. Belgedeki listeden işe yarayanlar typeName() (içinde bulunulan type'ın adı), getFileNameWithoutExtension(), getCurrentNamespace(), getDefaultNamespace(), suggestVariableName() ve complete(). Namespace'i regex ile üretmeye gerek kalmıyor, Rider projeyi biliyor.
Rider ayarları .DotSettings dosyalarında, XML olarak tutar. Ayarlar katmanlıdır: makine geneli "This computer", solution'ın yanında duran ve commit edilen "Solution team-shared" (<SolutionName>.sln.DotSettings) ve commit edilmeyen kişisel .DotSettings.user. Live template'i kaydederken Save To ile team-shared katmanı seçersen template solution dosyasının yanına yazılır. Settings Layers penceresinden (Manage Layers) bir dosyaya export ve import da yapılabiliyor. Bookstore'da tools/snippets/rider/bookstore.DotSettings dosyasının bir parçası:
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=7D2E4C1A9B3F4E8A8C6D5B4A3F2E1D0C/Shortcut/@EntryValue">bsfact</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=7D2E4C1A9B3F4E8A8C6D5B4A3F2E1D0C/Text/@EntryValue">[Fact]
public void $METHOD$_$SCENARIO$_$EXPECTED$()
{
$END$
}</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=7D2E4C1A9B3F4E8A8C6D5B4A3F2E1D0C/Scope/=B68999B9D6B43E47A02B22C12A54C3CC/Type/@EntryValue">InCSharpTypeMember</s:String>
Bu dosyayı elle yazmak zorunda değilsin; Rider'da template'i oluşturup team-shared katmana kaydetmek aynı satırları üretir. Ben anahtar yapısını gerçek bir açık kaynak projenin .sln.DotSettings dosyasından aldım. Template Tab ile açılır, Tab ve Shift+Tab ile değişkenler arasında dolaşılır; Ctrl+Alt+J seçili kodu bir template ile sarar.
Bu bölümde resmî belgelerden yararlanılmıştır.
Üç IDE'nin karşılıkları yan yana:
| VS Code | Visual Studio | Rider | |
|---|---|---|---|
| Dosya | .vscode/*.code-snippets (JSON) | .snippet (XML) | .DotSettings (XML) |
| Değişken | $1, ${1:Method} | $method$ + Literal | $METHOD$ |
| Son imleç | $0 | $end$ | $END$ |
| Seçili metin | TM_SELECTED_TEXT | $selected$ | $SELECTION$ |
| Hesaplanan değer | variable + regex transform | 3 function | macro'lar |
| Ekiple paylaşım | repo'daki .vscode | Code Snippets Manager, Add | team-shared katman |
Ekiple Paylaşmak
Önce Tahmin Et'teki sorunun cevabı .gitignore. Hem dotnet new gitignore hem Angular CLI'ın ürettiği dosya .vscode/* satırını içeriyor ve yalnız settings.json, tasks.json, launch.json ve extensions.json'a istisna tanıyor. Emre'nin commit'i o gün yaptığı diğer değişiklikleri içeriyor, ama dosya listesinde snippet yok: git add . ignore edilen dosyayı hiçbir uyarı vermeden atladı. git check-ignore hangi satırın dosyayı yuttuğunu gösteriyor:
$ git check-ignore -v .vscode/bookstore.code-snippets
.gitignore:388:.vscode/* .vscode/bookstore.code-snippets
Çözüm tek satır: !.vscode/extensions.json satırının altına !.vscode/*.code-snippets eklemek. Sonra aynı komut:
$ git check-ignore -v .vscode/bookstore.code-snippets
.gitignore:393:!.vscode/*.code-snippets .vscode/bookstore.code-snippets
! ile başlayan bir satırın eşleşmesi dosyanın artık ignore edilmediğini gösteriyor. Rider tarafında aynı .gitignore *.DotSettings.user satırını içeriyor; kişisel katman dışarıda kalıyor, team-shared dosya commit edilebiliyor. Bu doğru davranış, ama team-shared dosyaya kişisel bir ayar kaydetmemeye dikkat et.
Bir de IDE dışı araçlar var. espanso gibi text expansion araçları her uygulamada çalışır: commit mesajına eklenen sabit bir satır, sık yazılan bir ISBN (kitapların uluslararası standart numarası), test e-postası ada@example.com. Ayarı match/base.yml gibi bir YAML dosyasında trigger ve replace çiftleriyle tutulur. Kod kalıplarını bu araçlara koyma; IDE'nin bildiği scope, tab stop ve formatlama orada yok. Bunlar kişisel araçtır, dotfiles'ınla birlikte versiyonlanır (bu serinin dördüncü yazısı).
Üretimde Dikkat
Snippet dosyası da kod; pull request'te review edilir ve bozulabilir. Bookstore'da bunun için CI'da her build'de çalıştırılabilecek küçük bir kontrol script'i var: JSON okunabiliyor mu, her snippet'in prefix, body ve scope'u var mı, Visual Studio dosyasında her Literal'ın Default'u var mı ve kodda kullanılıyor mu, Rider dosyası geçerli XML mi:
$ python3 -I tools/snippets/check-snippets.py
VS Code: 4 snippets
Visual Studio: 'xUnit v3 fact' (CSharp, method decl)
Rider: 16 keys, shortcuts ['bsfact']
İkinci kontrol, snippet'lerin ürettiği kodun derlenmesi. Bookstore'un Directory.Build.props dosyasında AnalysisLevel değeri latest-recommended ve uyarılar hata sayılıyor. bsfact'in ürettiği ilk test bu yüzden build'i kırdı:
tests/Bookstore.Catalog.Tests/BookConfigurationTests.cs(10,17): error CA1707: Remove the underscores from member name Bookstore.Catalog.Tests.BookConfigurationTests.Configure_BookEntity_UsesIsbnAsKeyAndBooksTable() (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1707) [tests/Bookstore.Catalog.Tests/Bookstore.Catalog.Tests.csproj]
CA1707 public member adlarında alt çizgiyi yasaklıyor; test adlarındaki alt çizgi ise bilerek seçilmiş bir kural. Çözümü tests/Directory.Build.props içinde, yalnız test projeleri için uyarıyı kapatmak oldu:
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
<PropertyGroup>
<!-- Test adları Method_Scenario_ExpectedResult kuralını kullanıyor. -->
<NoWarn>$(NoWarn);CA1707</NoWarn>
</PropertyGroup>
</Project>
Snippet ile analyzer kuralı aynı ekip kararının iki yüzü; biri değişince öbürünü de güncelle. Kuralların kendisi Coding Conventions ve Ekip Standartları serisinde.
Sık Düşülen Tuzaklar
Birincisi bayat snippet. Birkaç yıl önce yazılmış bir component snippet'i bugün hâlâ şunu üretiyor olabilir:
@Component({
selector: 'app-book-card',
standalone: true,
templateUrl: './book-card.component.html',
})
export class BookCardComponent {
@Input() book!: Book;
}
Kod derlenir, ama Angular 22'nin ürettiği stilden üç noktada ayrılıyor: gereksiz standalone: true, .component son ekli dosya adları ve signal input yerine @Input() decorator'ı. Snippet'leri framework'ün major sürüm geçişinde gözden geçirilecekler listesine ekle; en kolay yol, snippet'in ürettiği kodu ng generate çıktısıyla yan yana koymak.
İkincisi snippet'e değer gömmek. Bir connection string snippet'i Password=example-password-change-me gibi bir değerle başlarsa, o değer bir gün gerçek şifreyle değiştirilip commit edilir. Snippet'te değer yerine ${1:ConnectionStrings__Bookstore} gibi ortam değişkeninin adını bırak; değer user-secrets ya da ortam değişkeninden gelsin.
Üçüncüsü prefix çakışması. prop ya da fact adında bir snippet yazarsan yerleşik olanla aynı listede görünür ve hangisinin seçildiği belirsizleşir. Ekip snippet'lerine ortak bir ön ek ver; Bookstore'da bs. Dördüncüsü scope unutmak: scope'suz bir global snippet her dilde önerilir. Beşincisi, en başta söylediğim gibi, snippet'i abstraction yerine kullanmak.
Küçük Bir Deneme
★☆☆ bsfact snippet'ini kendi editörüne kopyala ve [Theory] seçildiğinde altına bir [InlineData()] satırı da ekleyen ikinci bir snippet yaz. check-snippets.py ile JSON'un geçerli olduğunu doğrula.
★★☆ bsendpoints snippet'ine group.MapPost için ikinci bir tab stop ekle ve route adını (books) entity adından (Book) bir transform ile üret. Transform'u önce check-transforms.mjs içinde dene.
★★★ Kendi projendeki .gitignore dosyasında .vscode/* satırı var mı, git check-ignore -v ile kontrol et. Sonra Rider'da bsfact için bir live template oluştur, team-shared katmana kaydet ve oluşan .DotSettings dosyasını bu yazıdaki dosyayla karşılaştır.
Snippet tek bir dosyanın içindeki kalıbı çözüyor. Bir sonraki yazıda bir üst seviyeye çıkıyoruz: global.json, Directory.Build.props, analyzer ayarları, test projesi ve Dockerfile ile gelen yeni bir Bookstore servisini dotnet new template'iyle tek komutta üretmek ve Angular tarafında schematic'lere kısa bir bakış.