V červenci 2016 byla uvedena první ostrá verze nové .NET Frameworku, a sice .NET Core 1.0. Tato platforma je revoluční téměř po všech myslitelných stránkách.
Zaprvé je open source a hostována na GitHubu. Do vývoje, opravy bugů a různých výkonnostních optimalizací se zapojila celá řada lidí z komunity, a v issues jsou mnohdy k vidění velmi plodné a zajímavé diskuse. Microsoftu je tak více vidět pod pokličku a dá se lépe odtušit, kam bude vývoj směřovat.
Zadruhé je multiplatformní a již od začátku byla navržena tak, aby ji bylo možno provozovat na Linuxu a Macu. Podporuje i ARM a malá zařízení, například Raspberry PI Zero, které stojí 5 dolarů.
A do třetice ani téměř půl roku od jejího uvedení k ní zatím neexistuje ostrá verze toolingu a neustále se mění podoba projektových souborů a toho, jak se aplikace kompilují.
Pokud jste si již s .NET Core hráli, jistě jste narazili na spoustu různých problémů, divných chybových hlášek. Všechny tyto problémy jsou způsobeny neustále se měnícím toolingem a změnou formátu projektových souborů. V tomto článku si stručně zrekapitulujeme, k jakým změnám zde došlo a jak poznat starý formát projektů od nového.
Bezbřehý optimismus a JSON
Klasické projektové soubory (ty s příponou CSPROJ) v .NET Frameworku měly několik nepříjemných neduhů. Asi největším problémem bylo, že obsahovaly seznam všech C# souborů, které jsou zahrnuté v projektu. V případě, že člověk na projektu pracoval sám, to nepředstavovalo víceméně žádný problém, důvodů k ruční editaci CSPROJ souboru nebylo nikdy příliš mnoho, takže ani to, že je soubor dlouhý ničemu nevadilo.
V týmovém prostředí se ale jednalo o častou komplikaci a častý zdroj konfliktů v případě, že více lidí z týmu přidalo do projektu nějaké soubory. V mnoha případech se stávalo, že nově přidané soubory sice v source control systému byly, ale do projektu je bylo třeba přidat ručně. Nehledě na to, že přidání souboru automaticky v historii source control vygenerovalo i změnu projektového souboru, což zbytečně zapleveluje historii.
Po vzoru Node.js se Microosft rozhodnul nahradit korporátní a nepopulární XML formát dnes moderním JSONem. Objevil se tak soubor project.json, který celkem elegantním způsobem obsahoval všechny podstatné informace. Zároveň zavedl konvenci, že vše, co je ve složce projektu, je automaticky zahrnuto, a pouze věci, které jsou z kompilace vyloučeny, se zapisují do projektového souboru, a navíc ještě typicky pomocí wildcardu.
Větší integrace se dočkal také Nuget. V klasickém .NET Frameworku je Nuget jen takové chytřejší makro pro Visual Studio – instalace balíčku je jen automatizace činností, které byste museli dělat sami – stažení knihovny a případně dalších souborů, přidání reference do projektu a případně další úpravy CSPROJ nebo konfiguračních souborů projektu. Samotný build systém o existenci Nugetu v zásadě vůbec neví a u referencované knihovny nedokáže rozlišit, jestli se jedná o Nuget balíček, nebo o obyčejný DLL soubor, který někdo přidal ručně.
V novém projektovém formátu je integrace s Nugetem daleko užší a v souboru project.json se uvádí přímo názvy a verze balíčků, které mají být v projektu zahrnuty. Dokonce i reference projektů mezi sebou se tváří jako kdybyste instalovali Nuget balíček – v zásadě platí idea (převzatá z Node.js), že každý projekt je balíček, který se akorát nemusí nikam publikovat.
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.1",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"DotVVM": "1.1.0-alpha",
"DotVVM.AspNetCore": "1.1.0-alpha",
"Microsoft.EntityFrameworkCore": "1.0.1",
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.1",
"Microsoft.EntityFrameworkCore.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Identity": "1.0.0",
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0"
},
"tools": {
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final",
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
},
"frameworks": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
]
},
"net461": {}
}
}
Sekce dependencies obsahuje seznam Nuget balíčků, které se mají před kompilací do projektu nainstalovat.
Dále je zde sekce tools, která definuje rozšíření do command line utility dotnet, která se dá použít například ke spuštění webové aplikace pomocí serveru Kestrel (stačí spustit v projektovém adresáři příkaz dotnet web), pro tvorbu migrací v novém Entity Framework Core (dotnet ef …) atd.
Sekce frameworks specifikuje, pro které platformy se má aplikace kompilovat. Vzhledem k tomu, že mnoho knihoven chce podporovat jak nový, tak starý .NET, je možné zde uvést více frameworků, a kompilátor poté vytvoří dvě verze – jednu pro .NET Core, druhou pro plný .NET 4.6.1. Každý framework může ještě uvnitř obsahovast sekci dependencies, kam by se uvedly balíčky specifické pro danou verzi .NET Frameworku.
Vystřízlivění
Po krátkém období euforie s formátem JSON nastalo vystřízlivění, během kterého se ukázalo, že by bylo nereálné předělat vše, co dnes běží na MSBuildu (protože CSPROJ je jen skript pro MSBuild). Proto bylo oznámeno, že se project.json ruší a vracíme se k zpátky CSPROJ, byť ve změněné podobě, která řeší hlavní neduhy.
Současně s uvedením Visual Studia 2017 RC se tedy přešlo na nový formát projektů, který má též příponu CSPROJ. Nejzásadnější změnou je, že Nuget balíčky se referencují pomocí elementu PackageReference, což je zlepšení oproti původnímu stavu, kde v souboru packages.config byl uveden seznam balíčků, a v projektovém souboru se balíčky přidávaly jako normální reference na DLL.
Současně se v projektovém souboru objevily wildcardové importy souborů s příponou CS, což nás konečně zbaví nutnosti řešit merge konflikty pokaždé, kdy více lidí přidá soubor. Navíc Visual Studio nyní sleduje změny ve filesystému a nové soubory přidá automaticky bez nutnosti projekt reloadovat.
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<AssemblyTitle>DotVVM</AssemblyTitle>
<TargetFrameworks>netstandard1.6;net451</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" Exclude="node_modules;bin\**;obj\**;**\*.xproj;packages\**" />
<EmbeddedResource Include="**\*.resx" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="node_modules\**" />
<EmbeddedResource Remove="node_modules\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk">
<Version>1.0.0-alpha-20161104-2</Version>
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="NETStandard.Library">
<Version>1.6.0</Version>
</PackageReference>
...
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.ComponentModel.DataAnnotations" />
</ItemGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.6' ">
<DefineConstants>$(DefineConstants);DotNetCore</DefineConstants>
</PropertyGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Projekty též podporují kompilaci pro více frameworků zároveň (element TargetFrameworks) a pomocí klasických podmínek v MSBuildu je možné specifikovat reference nebo jiná nastavení pro konkrétní platformy.
Pokud ve Visual Studio 2017 RC otevřete projekt se souborem project.json, Visual Studio jej automaticky zupgraduje, což je příjemné. Nefunguje to stoprocentně, nicméně drtivou většinu projektů nám to zkonvertovalo správně. Migraci lze také provést spuštěním dotnet migrate z příkazového řádku.
Úkrok stranou
Včera (12. 12. 2016) Microsoft uvedl update pro Visual Studio 2017 RC, které mění formát CSPROJ souboru. Výhodou je, že projektový soubor je mnohem stručnější. Nevýhodou (a to dost zásadní) je, že pokud jste project.json upgradovali na CSPROJ, neexistuje oficiální upgrade cesta z nového CSPROJ formátu na tento nejnovější. Více informací lze najít v Release Notes.
Vzhledem k tomu, že DotVVM už jsme na CSPROJ zupgradovali, nezbylo mi než si napsat tool, který migraci na nejnovější formát usnadní. Najdete jej na GitHubu.
Doufejme, že Microsoft už moc dalších změn v toolingu dělat nebude, a že jej co nejdříve konečně dotáhne do finální verze. Je pochopitelné, že investují hodně úsilí do toho, aby tooling byl perfektní, a přestože se mi myšlenka project.jsonu líbila, nový formát CSPROJ souboru je též použitelný, řeší všechny problémy, a nebude nutné kvůli němu předělávat tisíce nástrojů, které spoléhají na MSBuild. Současná situace je dost nešťastná, protože ať hledáte jakýkoliv návod, najdete nejčastěji verzi pro project.json. Pro nové projektové soubory moc návodů zatím není.