Bevezetés a .NET Core világába
Bevezetés a .NET Core világába Nagy Gáspár független konzulens, olyan csapatokat oktat és segít, akik fejlesztői munkájuk minőségét és hatékonyságát agilis tesztelési módszerekkel, azon belül is viselkedésalapú szoftverfejlesztéssel (behavior driven development - BDD) szeretnék növelni. Gáspár a megalkotója és jelenleg is vezető fejlesztője a nyílt forráskódú SpecFlow tesztelési eszköznek, amely meghatározó BDD eszköz a .NET platformon. Több mint 15 éve foglalkozik szoftverfejlesztéssel, korábban szoftvertervezőként és fejlesztői coachként is dolgozott. Rendszeres előadó nemzetközi konferenciákon és a Scrum Alliance akkreditált oktatója a Certified Scrum Developer programban. Microsoft Certified Professional az Application Lifecycle Management témakörben. Gáspárt megtalálhatod a twitteren (@gasparnagy), a blogján (http://gasparnagy.com) vagy vállalkozásának (Spec Solutions) weboldalán (http://www.specsolutions.eu).
TARTALOMJEGYZÉK Tartalomjegyzék ...................................................................................................................................................1 Bevezetés..............................................................................................................................................................2 minden mozgásban van ....................................................................................................................................2 A .NET core release-ek rövid áttekintése .........................................................................................................3 Ismerkedés négy állomásban ...........................................................................................................................3 1. állomás: ahol egy desktop appot írsz, és a lehető legnagyobb piacot próbálod elérni ...................................3 2. állomás: ahol az ASP.NET webalkalmazást linux szerveren szeretnéd hostolni ...............................................6 Cross-compilation .............................................................................................................................................8 3. állomás: ahol NuGet package-ként szeretnél olyan könyvtárat létrehozni, ami számos platformon és frameworkön használható................................................................................................................................. 10 A könyvtárad elérhetővé tétele olyan platformokra, amiket nem is ismersz ............................................... 13 4. állomás: ahol korlátozni és kontrollálni szeretnéd, a framework melyik részei települjenek az appoddal .. 15 A reflection történet ...................................................................................................................................... 16 .NET Native .................................................................................................................................................... 17 Összegzés ........................................................................................................................................................... 19
•••
1/22
Bevezetés a .NET Core világába
BEVEZETÉS Mikor ezt a cikket elkezdem írni, ha egy új webalkalmazást hozok létre Visual Studio 2015 Update 1-gyel, a project.json fájl két target frameworköt sorol fel: dnx451 és dnxcore50. Ha új dnx-style console alkalmazást hozok létre, akkor net451 és dotnet5.4-et kapok. Amennyiben érted, miért történik mindez, nem is kell tovább olvasnod. Készen állsz az új dolgokra (te vagy az, Scott?). A cikket 2016. júniusában fejezem be, mikor is a .NET Core 1.0.0 RC2, Visual Studio 2016 Update 2 és a .NET Core VS 2015 Tooling Preview 1 kint van már. Ha a fentieket újracsinálom, netcoreapp1.0, net461, netstandard1.5 framework referenciákat kapok. Más, világosabb, de legtöbbünk számára még mindig némi magyarázatra szorul. Tarts velem ezen az utazáson, hogy mindezeket az új dolgokat megérthesd. Számos kérdésre próbálok választ találni, mint például
Mi a .NET Core?
Mi az ASP.NET Core? Hogyan kapcsolódik a .Net Corehoz?
Mi a .NET 5.4? Lemaradtam valamiről?
A portolható osztálykönyvtárak (portable class libraries) már vége?
Mi a .NET Native, és hogyan kapcsolódik a .NET Core-hoz?
Mi a netcore5 target, és hogyan kapcsolódik a .NET Core-hoz?
Mi a DNX? Ugyanaz, mint a .NET Core?
Hogy kerül a .NET CLI a képbe?
Uh, már most elég sok. Ahogy haladunk előre, megpróbálom egyenként megválaszolni őket, de először szeretnék áttekintést nyújtani arról, mit értettem meg ezekből az új koncepciókból különböző cikkek, az opensource kód és szakmai beszélgetések alapján. Pár ponton tévedhetek – ha találnál ilyet, kérem, tudasd velem. Ez egy utazás. És amennyire én látom, nem a közeljövőben fog véget érni. MINDEN MOZGÁSBAN VAN Az új dologról szóló összes cikk és bejelentés azzal a nyilatkozattal kezdődik, hogy ez az egész csak beta, RC, egyéb, így a dolgok változhatnak. Megszoktam már az ilyen jellegű bejelentéseket, de a korábbi .NET releaseekben (az én első tapasztalataim a .NET 1.0 béta verzióból származnak) mindez inkább formalitásnak számított. Igen, a béták után mindig voltak kisebb változtatások, és a dolgoknak először csak kódneve volt, de a fejlesztések mindig könnyen követhetőek voltak. Mára a Microsoft az open-source irányába indult el. És ez nem csupán a kódlicenszről szól. Az is változott, hogy az ötletek és az design hogyan fejlődik, illetve a visszajelzéseket hogyan kezelik. Végül is ez nem rossz. Ám nagyon szokatlan élmény a .NET fejlesztők számára.
•••
2/22
Bevezetés a .NET Core világába
Eddig a döntések a mi zónánkon kívül születtek, és mi csak kívülről figyeltük, más közösségek (mint a Java) hogyan szenvednek meg a konszenzusért. És most mi vagyunk soron. Tehát ha azt mondják, változik, ez azt jelenti, tényleg változik. Azt hiszem, ez a zűrzavar egyik jelentős forrása. (A cikket próbálom rendszeresen frissíteni, hogy a legfrissebb változásokkal is naprakész legyek.)
A .NET CORE RELEASE-EK RÖVID ÁTTEKINTÉSE Egy új open-source .NET framework ötlete 2014-ben kezdődött egy új ASP.NET verzióval (akkoriban ASP.NET vNextnek nevezték). Az ASP.NET Core 1.0 – ez a végleges név, jelenleg RC2 fázisban van. Időközben az ASP.NET vNextből nőtt ki az új .NET framework, a .NET Core 1.0, ami pillanatnyilag ugyanabban a release sémában van, mint az ASP.NET Core, azaz ugyanúgy szintén RC2 státuszban. A jelenlegi RC2 “go-live” licensszel rendelkezik (a Microsoft már hivatalosan támogatja). A végleges RTM (release) 2016. június végére várható. Bár a frameworkök nemsokára véglegessé válnak, a kapcsolódó tooling még mindig a Preview 1 státuszban van, így még mindig igen messze van a végleges állapottól. Ezeket a következő Visual Studo verzióra fogják stabilizálni (Visual Studio “15”). Kissé meglepő lehet, hogy a tooling itt nem csupán a Visual Studio varázslókat és a csilllogó editor dialógusokat jelenti, hanem a command line toolokat és a project file formátumokat is, amiket minden .NET Core alapú projektnek használnia kell. Kicsit ijesztőnek tűnhet, de majd meglátjuk. Az a terv, hogy akármikor változik is a fájl formátum, a Microsoft biztosítani fogja a szükséges migrációs eszközöket, hogy azok a projektek, amelyek már elkezdték használni a .NET Core-t vagy az ASP.NET Core-t, könnyen áttérhessenek. A release tervvel kapcsolatos további információk itt találhatók.
ISMERKEDÉS NÉGY ÁLLOMÁSBAN Míg az új dolgokat kutattam, reméltem, hogy sikerül megtalálnom az “egyedüli választ”, ami mindent tisztába tesz. Ehelyett rá kellett jönnöm, hogy nem “egy dolog” van (mint a .NET Core), hanem a .NET-alapú fejlesztés és alkalmazások számos különböző továbbfejlesztése. Közülük számos ortogonális a többire. Így megpróbálom őket a használat szemszögéből, a tanulmányutat állomásokra lebontva megközelíteni – amúgy is ez az egész így kezdődött el. Akkor irány az első állomás!
1. ÁLLOMÁS: AHOL EGY DESKTOP APPOT ÍRSZ, ÉS A LEHETŐ LEGNAGYOBB PIACOT PRÓBÁLOD ELÉRNI Tehát van egy nagyszerű ötleted egy új desktop alkalmazásra. Csomó időd elmegy a kódolásra, de még mindig csak Windows alatt fut, mivel .NET-en készítetted. – Ez tipikus kiinduló pont lehet. (Amint látni fogod, ezt az adott szcenáriót még nem támogatják. Viszont úgy vélem, jó kezdete a mi utazásunknak.)
•••
3/22
Bevezetés a .NET Core világába
A megoldás erre többé-kevésbé csak a Mono. A Mono Linux és OSX alatt is fut. Ez tipikusan úgy működött, hogy az alkalmazást Windowson kellett lefejleszteni, de a .NET Framework feature-öket nagyon óvatosan kellett használni, csakis azokat a részeket, amiket már a Monóban is implementáltak. Az alkalmazásod lefordított assemblyjei binárisan kompatibilisek voltak a Mono runtime-mal, így az egyetlen módja annak, hogy ellenőrizd, Monoval is működik-e, az, hogy kipróbálod, teszteled, stb. a Mono újra implementálta 1) a futtató környezetet, azaz a runtime-ot, 2) néhány .NET feature platform-specifikus részét (pl. System.IO), és 3) a platform-független tisztán logikai részt is (pl. System.Collections). Igen, ezt a harmadikat is újra kellett implementálni, mivel a .NET zárt forráskódú volt. A platform-független dolog újra implementálásának szükségessége és az ebben gyökerező összes probléma a Microsoft számára is kényelmetlen volt, és bár hajlandóak voltak az implementációjukat a Monoval megosztani, kiderült, hogy ez nem olyan egyszerű. A legszembetűnőbb probléma az volt, hogy a .NET framework assemblyk és feature-ök nem voltak úgy elizolálva, hogy a platform-független részt könnyen el lehessen különíteni. Pl. számos .NET assembly rendelkezett némi platform-függő kóddal is – például Win32 API hívások vagy COM integráció: a .NET assemblyk túl nagyok voltak. A Microsoft ideiglenes kerülő megoldást alkalmazott, megfelelő licensszel megosztotta a “.NET reference code”-ot, így az alternatív runtime-ok, mint a Mono, fejlesztői legalább “copy-paste”-elni tudták az implementációs részeket. Közben elkezdtek dolgozni a framework átstrukturálásán, olyan módon, hogy az modulárisabb, és a platform-független kód más runtimeokkal megosztható legyen. Ez a .NET Core? Majdnem. Ez tulajdonképpen a .NET Core alap osztálykönyvtára (base class library), a CoreFX. És ez nyílt forráskódú. A CoreFX moduljai nem csupán elkülönülő assemblyk (mint a System.Collections.dll), de NuGet package-enként vannak csomagolva és terjesztve a NuGet.org-on keresztül (a package neve és verziója passzol az assemblyhez). Így a disztribúciós és a frissítési folyamat zökkenőmentesebb. Erre a témára később még visszatérek.
A normál .NET framework futtató környezete (runtime) részben az mscorlib.dll-ben van, részben pedig más olyan fájlokban, amik a .NET telepítésekor felinstallálódnak a gépre. De sajnos az mscorlib nemcsak runtimeos dolgokat tartalmaz, hanem a base class library jelentős részét is. Így az átstrukturálás részeként a runtime
•••
4/22
Bevezetés a .NET Core világába
és a könyvtárak közötti határvonalat is le kellett tisztázni, az mscorlib-et pedig szét kellett választani. Ennek eredményeképpen olyan teljesen új runtime jött létre, ami támogatja a CoreFX struktúrát. Ez a runtime is nyílt forráskódú, és része a .NET Core-nak, ez a CoreCLR. A CoreCLR-t úgy tervezték, hogy ezzel könnyedén támogathassák a különböző platformokat. Jelenleg a CoreCLR nem csupán a Windowst támogatja, hanem létezik egy kész implementáció Linuxra (Red Hat, Debian, Ubuntu, Centos) és OSX-re is. A .NET Core, így az új runtime (CoreCLR) és a base class library (CoreFX) a felhasználó szempontjából hasonlít a .NET Frameworkre (pl. van egy System.Collections.List
osztály). Belső struktúrája viszont, főleg a vashoz közelebb eső (runtime, platform-specifikus funkciók) teljesen eltér. Emiatt sem a jelenlegi .NET framework, sem a Mono nem tud “futni” a CoreCLR runtime-on. Amennyiben kezdettől fogva velem vagy ezen a z utazáson, emlékszel, hogy a Mono project “megsegítésénél” kezdtünk, de olyan új runtime létrehozásáig jutottunk, ami a Mono által nem használható, sőt, a CoreCLR Linux supportja a linuxos .NET fejlesztőkre támaszkodik. Ez azt jelenti, hogy a Mono halott? Nem. Vagy legalábbis még nem. Arról van szó, hogy a .NET Core projekt jelenleg olyan szerveralkalmazásokra fókuszál, amik kevésbé függnek az OS specialitásaitól. Így nem létezik .NET Core-ra portolt UI könyvtár (mint a WPF vagy a WinForms), kivéve a console API-t . Még a térképen sincsenek rajta. Tehát egyelőre nem kell aggódni a Monóért (és a normál .NET frameworkért sem). De természetesen senki sem áll az utadba, ha a létező .NET Core könyvtárakra építve írsz egy cross-platform UI könyvtárat. Nem lennék meglepődve, ha valaki nemsokára előállna egy ilyen lépéssel. Ámde. Ahogy láttad, első állomásunk – cross-platform desktop alkalmazás írása – még nem lehetséges .NET Core-ral. Így nézzünk egy másikat: cross-plaform webalkalmazás. Mit tudtunk meg eddig? A .NET Core egy teljesen új .NET-szerű framework, ami vékony cross-platform runtime-ból (CoreCLR) és olyan (cross-platform és platform-független) könyvtárakból (CoreFX) áll, amik NuGet packageekként tölthetők le a NuGet.org-on keresztül.
Sem a Mono, sem a normál .NET framework nem tud a .NET Core-on “futni”, még csak a CoreCLR-en sem.
A felhasználó nézőpontjából (pl. az API), a .NET Core és a normál .NET framework nagyon hasonlít egymáshoz, de a .NET Core-nak kevesebb funkciót támogat, pl. még nincs gazdag UI könyvtár. Ez a normál .NET Framework és a Mono privilégiuma marad a közelebbi jövőben.
Eddigi összegzés Mi a .NET Core, és miért hívták először .NET 5-nek? Mert ez egy olyan új .NET (-szerű) framework, ami esetleg majd helyettesítheti a normál .NET Frameworköt, ami jelenleg a 4.6.2 verziónál tart.
•••
Miért nevezték át utána .NET Core 1.0-ra? Mert rájöttek, hogy a közeljövőben a .NET Core nem lesz képes a normál .NET Frameworköt helyettesíteni, hanem ezek párhuzamosan, egymás mellett fognak fejlődni.
5/22
Bevezetés a .NET Core világába
2. ÁLLOMÁS: AHOL AZ ASP.NET WEBALKALMAZÁST LINUX SZERVEREN SZERETNÉD HOSTOLNI Tehát támadt egy nagyszerű ötleted egy webes alklamazásról. Rengeteg időd elmegy a kódolással, de csak Windows és IIS (Internet Information Services) alatt fut, mert .NET-ben írtad. – Ez egy másik tipikus kezdőpont. Miért akarod Linuxon hostolni? Mert a Linux-alapú felhő VM olcsóbb; mert az ügyfeled Linux szervereket használ, vagy mert egyszerűen több tapasztalatod van Linux szerverekkel. Az első ötlet természetesen a Mono lenne. A Mono támogatja az ASP.NET-et, de csak az ASP.NET 2.0-t, ami már elég régi (a jelenlegi verzió az ASP.NET 4.6). Így igazából nincs is igazi opció. Mivel a Microsoft egyre inkább elmozdult a (felhő alapú) szolgáltatások biztosítása irányába, az, hogy ezen szolgáltatások milyen operációs rendszereket támogatnak, kevésbé fontos. Így az ASP.NET Linuxos támogatásának hiánya problémásnak tűnt számukra, és megoldást kerestek a cross-platform webs alkalmazások írására. Szándékosan mondtam, hogy “megoldást”, és nem “frameworköt” vagy “platformot”. Ugyanis az ASP.NET cross-platformra bővítésével két fő problémát kell megoldani: 1. Az ASP.NET erősen kötődik az IIS-hez – ez egy natív (nem .NET) webszerver. Az IIS cross-platformra bővítése így nem opció. 2. Az ASP.NET által használt .NET Frameworknek cross-platformnak kell lennie. Már láttuk, hogy a második problémára a .NET Core úgy tűnik, megoldással szolgál. A korlátozások (pl. nincs UI könyvtár) nem érintik ezt a scenariót. Ez jónak tűnik. Az IIS-től való függés inkább problematikus. Ez a függőség nem csak a portolhatóság akadálya, de a tesztelés szempontjából is nyűg volt. Más platformokon, mint pl. a Rubyn, nagyon egyszerű automatizált tesztek elvégzéséhez in-process webszervert elindítani. IIS-sel vagy IIS Express-szel mindez nem volt lehetséges. Mivel az IIS-től való függőség annyira szerves része volt az ASP.NET-nek, és mivel az ASP.NET infrastruktúra amúgy is elavulttá és kényelmetlenné kezdett válni a modern webes alkalmazások számára, a Microsoft úgy döntött, hogy az ASP.NET-et immár open-source projektként elölről kezdve újra implementálja. Ez az ASP.NET Core. A felhasználó szempontjából az ASP.NET Core kevésbé hasonlít az ASP.NET-hez, mint a .NET Core a .NET-hez. Ez azért van, mert az új frameworkkel egyéb modernizálást is véghezvittek, pl. egyszerűbb HTTP request pipeline-t vezettek be. Mindazonáltal ha MVC-t használsz, akkor továbbra is ismerős lesz a környezet. A modernizálás miatt az ASP.NET-nek vannak olyan részei, amelyeket soha nem visznek át az ASP.NET Core-ba, és vannak mások is, amik tervben vannak, de még nem készültek el (pl. SignalR). Tehát ez egy még folyamatban lévő munka.
•••
6/22
Bevezetés a .NET Core világába
OK, tehát, mivel az ASP.NET Core csupán három betűvel több, mint a .NET Core, feltételezhetnénk, hogy az ASP.NET Core-t a portolható .NET Core-ra fejlesztették. Öhöm. Nem. Nem igazán ismerem az emögött rejlő okokat: vagy nem akarták, hogy a .NET Core az IIS alatt fusson, vagy nem akartak addig várni, míg a .NET Core az új ASP.NET indulása előtt “elkészül”. Vagy talán vannak egyéb más okok is. De a lényeg, hogy jelenleg az ASP.NET Core mind a .NET Core-on és a normál .NET Frameworkön is egyaránt fut. Milyen jó, hogy a kettő külső API-ja nagyon hasonló!
Álljunk most meg, és nézzük meg, meddig jutottunk. Mit tudtunk meg eddig? Az ASP.NET Core az ASP.NET teljesen új implementációja. Inkább a modern webes alkalmazások szükségleteire fókuszál (pl. egyszerűbb HTTP request pipeline), és nem függ közvetlenül az IIS-től.
Az ASP.NET mind a .NET Core és a normál .NET Framework alatt egyaránt fut.
Az ASP.NET Core nem implementálja az ASP.NET összes funkcióját (vagy mert elavultak, vagy mert több idő szükséges a befejezésükhöz). Így lesznek olyan scenariók, amikhez időnként a régi ASP.NET frameworkre lesz szükség.
Eddigi következtetések Miért nevezték az ASP.NET Core-t először ASP.NET 5-nek vagy ASP.NET vNextnek? Mert ez egy új ASP.NET framework, ami egyszer esetleg helyettesítheti a normál ASP.NET frameworköt.
Majd miért nevezték át ASP.NET Core 1.0-nak? Mert rájöttek, hogy a közeljövőben az ASP.NET Core nem lesz képes a normál ASP.NET Framework helyettesítésére, hanem párhuzamosan fognak fejlődni.
Miért látok net461-t és netcoreapp1.0-t (vagy dnx451-et és dnxcore50-et VS2015 Update 1-gyel) target frameworkökként, ha egy új ASP.NET Core projektet hozok létre? Mert egyaránt tud futni.NET Coreon (netcoreapp1.0) és a normál .NET Frameworkön (net461).
Miért van benne a “Core” a névben, ha a normál .NETFramework alatt is fut? Hát igen. Jó kérdés.
•••
7/22
Bevezetés a .NET Core világába
CROSS-COMPILATION Ok, eddig minden rendben, de várjunk csak egy kicsit. Azt mondtuk, a .NET Core és a .NET Framework nagyon hasonló API-val rendelkezik. Mégis különböznek egymástól. Nemcsak különböző a runtime, de különböznek a class libraryk, az assemblyk és az osztályok. Pl. ha a List -t .NET-ből akarod használni, a System.dll-t kell bereferálni. Ha a .NET Core-ból szeretnéd használni, a System.Collections.dll-t kell bereferálni (vagy inkább az őt becsomagoló NuGet package-et). Így ugyanaz a (lefordított) alkalmazás nem futhat mindkét framework alatt! Azzal a céllal kezdtünk, hogy az IIS-től való függőséget eltávolítjuk az ASP.NET-ből, és amiatt, hogy (talán csak átmenetileg) az ASP.NET-nek mind a .NET és a .NET Core alatt is működnie kell, egy jóval nagyobb problémához értünk. Semmi pánik, van megoldás. Csak kicsit hátrébb kell lépnünk, hogy megértsük. Az ASP.NET mindig elő- és utókompilált dolgok keveréke volt. Lehetett C# kódot írni olyan osztályokba, amik assemblyként lettek lefordítva és telepítve, viszont néhány C# kódrész (pl. az, amit a view-khoz adtál hozzá) forráskódként lett telepítve, és futás közben lett fordítva, mikor az első lekérdezés kiszolgálásra került. Más frameworkök, mint a Ruby vagy a node csak a forráskódként telepített modellt használják, és nagyon sikeresek! Ez érthető, mert a forráskódként való telepítéssel felmerülő tipikus problémák, mint a kéretlen módosítások vagy a szellemi tulajdon védelme, nem érintik a webes alkalmazásokat. Tehát ha a .NET és a .NET Core API-ja amúgy is hasonló, ugyanaz a C# kód nagy valószínűséggel mindkettővel működni fog. Ezen előnyt felhasználandó, az új ASP.NET Core infrastruktúra új utókompilációs modellt is bevezetett, ahol a webes alkalmazások elsősorban forráskódként kerülnek telepítésre, és menet közben lesznek lefordítva a célkörnyezet lehetőségeinek függvényében. Ha a célkörnyezet Linux .NET Core-ral, a kód arra fog fordulni (netcoreapp1.0, korábbi nevén dnxcore50), ha ez Windows .NET 4.6.1-gyel, ugyanaz a forráskód fog fordulni erre a másikra (net461, korábbi nevén dnx461). A fejlesztői környezet alatt, ahol ideális esetben mindkét framework installálva van, mindkettőre fordul, a kódkompatibilitás ellenőrzése érdekében. Ez jó ötlet, kivéve, hogy a jelenlegi MsBuild-alapú projektmodell nem igazán támogatja a keresztkompilációt (egy project több target platformra tud fordulni). További probléma, hogy az MsBuild része a normál .NET Frameworknek, és még nem portolták át a .NET Core-ra. Így a cross compilation létrehozásához az MsBuild nem számított opciónak. Ehelyett egy új build rendszer került bevezetésre, ami json fájlokat használ (project.json) az MsBuild XML fájlok helyett a projekt részleteinek leírására. 2016. májusában viszont már úgy tűnt, a gyorsabb és zökkenőmentesebb tool support érdekében a project.json a “release-elés előtt elhalálozott” koncepciók polcán fog landolni. A Microsoft úgy döntött, megtartja az MsBuildet és az XML formátumot, és ezeket cross-compilationnel, helyi NuGet package referenciákkal és más olyan dolgokkal terjeszti ki, amiket a project.json-ban annyira szerettünk… nos, kivéve a kevésbé bőbeszédű és könnyebben szerkeszthető json formátumot. Mivel ez még mindig csak terv, továbbra is project.json-t használom a cikkben. Ám mivel a fordítás általában futás közben történik (kivéve a fejlesztés során), ez az új rendszer nem csupán egy build rendszer, hanem egy futtató környezet is, ami “futtatni” tudja a webes alkalmazást, beleértve a szükséges fordításokat is. Ez az oka annak, amiért ezt az új infrastruktúrát .NET Execution Environmentnek vagy DNX-nek nevezték (a támogató build tool neve .NET Development Utility – DNU, de általában erre nincs szükség). Mivel a .NET Core működési tere és hosszú távú céljai kiterjedtebbek lettek, a DNX/DNU toolok nehézkessé váltak, és helyettük (még a release-elésük előtt) a .NET Command Line Tools, azaz .NET CLI, vagy egyszerűen
•••
8/22
Bevezetés a .NET Core világába
“dotnet” került bevezetésre. Míg ezek között a toolok között van némi különbség, a fő koncepció ugyanaz maradt: .NET Core alkalmazások fordítása és futtatása. Sajnos a .NET CLI elég későn került bevezetésre, az ASP.NET Core RC1 után, mikorra a DNX név már elég széles körben elterjedt. Ez igaz az új technológiát felfedezőkre (a DNX a .NET Core egyfajta szinonimájának számított), illetve a különböző toolok és frameworkök elnevezésére is. Például a .NET Core framework rövid neve dnxcore50 volt. Ezek a nevek már változtak, de az RC1-hez létrehozott toolokkal és könyvtárakkal való visszafele kompatibilitáshoz a project.json “frameworks” szekciójának netcoreapp1.0 node-ja az “importok” között a régi framework neveket is felsorolja, azt deklarálva ezzel, hogy olyan könyvtárakat is képes importálni, amik ezen RC1 framework nevekhez készültek. A .NET CLI hasonló módon működik, mint más platformok futtatási környezetei, mint pl. az npm a node-hoz. Így olyan futtatási opciókat vezet ki parancsokként (command), amelyek a projekt vagy a projekt által használt bármilyen framework által definiálhatók. Pl. egy olyan webes alkalmazás, ami entity frameworköt használ, az ef parancsot használhatja az Entity Framework műveleteinek elvégzésére, mint pl. a migrációk. Ezek a parancsok a parancssorból hívhatók meg, ld. pl. dotnet ef …. Léteznek előre definiált parancsok, pl. run. Egy ASP.NET Core alkalmazás esetén a dotnet run parancs meghívása a webes alkalmazást indítja el az új Kestrel webszerver segítségével. Az ASP.NET Core és a .NET CLI az igény szerinti fordítást kiemelten kezeli, így a webes alkalmazások (vagy az általa használt könyvtárak) ki is terjeszthetik a fordítási folyamatot. Még mindig megvan az a probléma, hogy egy környezetben (mint a fejlesztői) több target framework is fel van telepítve, így ki kell választani, melyik frameworköt használjuk, mikor a dotnet run parancsot meghívjuk. Ehhez extra --framework opció használható. (Korábban a target framework kiválasztásához a .NET Version Manager (dnvm) használatára volt szükség.) Ez a új fordítási és futtatási környezet támogatja az ASP.NET Core-t, azaz a webes alkalmazásokat és a console alkalmazásokat is. Tehát ha szeretnél létrehozni eg új forráskódként telepített cross-platform console alkalmazást, akkor ezt ugyanilyen stílusban lehet csinálni. Fontos megemlíteni, hogy ezzel a modellel megszabadulhatunk a gépre installált frameworktől való függőségtől. Ez jótékony hatással van az olyan szerverekre, amelyek több webes alkalmazást hostolnak különböző frissítési ciklusokkal. Ezt részleteiben később megvizsgáljuk.
•••
9/22
Bevezetés a .NET Core világába
Mit tudtunk meg eddig? A .NET CLI (.NET Command Line Tools) forráskódként telepített, igény szerint fordított, cross-platform alkalmazásokhoz való futtatási környezet. A funkcionalitásokat olyan parancsokon keresztül vezeti ki, amik a console-ból a dotnet mycommand-dal hívhatók meg. A parancsok, akárcsak az alkalmazás (=projekt) többi része, a project.json fájlban vannak meghatározva.
A DNU (.NET Development Utility), a DNX (.NET Execution Environment) és a DNVM (.NET Version Manager) az RC1 tooljai voltak projektek futtatásához, buildeléséhez és konfigurálásához. A .NET CLI felváltotta ezeket a toolokat, így ezekre már nincs szükség.
A project.json nemsokára elavulttá fog válni, és funkcióit az MsBuild veszi át (ld. bejelentés).
Eddigi következtetések A DNX ASP.NET specifikus? Igen is és nem is. Maga a DNX egy tool, amit az ASP.NET Core-hoz fejlesztettek ki, de console alkalmazások futtatásához is használható. Viszont a forráskódként való telepítési stílus legvalószínűbben csak a webes alkalmazások körében lesz népszerű.
A .NET CLI ASP.NET specifikus? Nem. Részint ez az oka annak, miért váltotta le a DNX-et.
A .NET CLI .NET Core specifikus? Nem. A .NET CLI toolok a normál .NET Frameworkre is tudnak projekteket buildelni és futtatni.
3. ÁLLOMÁS: AHOL NUGET PACKAGE-KÉNT SZERETNÉL OLYAN KÖNYVTÁRAT LÉTREHOZNI, AMI SZÁMOS PLATFORMON ÉS FRAMEWORKÖN HASZNÁLHATÓ Az előző állomáspokon asztali és webes alkalmazások írására összpontosítottunk. Láttuk, hogy a crossplatform asztali alkalmazásokra vonatozóan a .NET Core fog majd megoldással szolgálni (egyelőre viszont még nem); a webes alkalmazásoknál az futás közben fordított ASP.NET Core Framework segíthet, ami a környezet lehetőségeinek függvényében vagy .NET Core-ra vagy normál .NET Frameworkre fordít. Több projektben használható könyvtár írásakor kicsit más megoldásokra van szükségünk. Ezek a könyvtárak hagyományosan fordított assemblyként és nem forráskódként vannak terjesztve (legalábbis a jelenlegi NuGet infrastruktúra ezt a modellt részesíti előnyben). Tehát ebből a szempontból nagyon hasonlítanak ahhoz, amit az asztali alkalmazásoknál láttunk. Ameddig a .NET Core nem támogatja a különböző operációs rendszerek és eszközök széles skáláját, a könyvtáradat inkább több különböző target frameworkhöz érdemes fordítani (crosscompilation), hogy az ügyfeleid azt válasszák, ami az ő igényeiket a legjobban kielégíti. (A NuGet támogatja ezt. Egyetlen NuGet package-be a könyvtárad több lefordított változatát is becsomagolhatod.) Így ebből a szempontból inkább hasonlít ahhoz, ahogyan az ASP.NET Core webes alkalmazások működnek.
•••
10/22
Bevezetés a .NET Core világába
Van egy kalapácsunk (a .NET CLI toolok a project.json fájllal) és egy olyan problémánk, ami szinte olyan, mint egy szög, tehát próbáljuk meg használni azt, amink van! Az ASP.NET Core (!) részeként project.json alapú class library is létrehozható. Ezek ki tudják használni a .NET CLI keresztfordítás funkcionalitását, így csipet fűszerrel és némi varázslattal a class library számos target frameworkre lefordítható és NuGet package-be csomagolható! Hurrá! Ez tulajdonképpen nagy előny, még ha nem is vesződünk a .NET Core-ral! Előtte igen nehéz volt keresztfordításos és multi-platform NuGet package-eket létrehozni (ez volt a shared projektek és a manuális scriptelés időszaka). Ez most már lehetséges. De várjunk csak! A cross-platform könyvtárproblémára már volt megoldásunk! A portolható osztálykönyvtárak (portable class library, PCL)! Mi lett velük? Tulajdonképpen semmi, és úgy tűnik, amíg a .NET Core-t nem használják széles körben az összes operációs rendszeren és eszközön, addig szükségünk lesz rájuk. Vagy… mégsem? Ha a NuGet amúgy is képes a könyvtár különböző fordításait csomagolni, miért van szükségünk más módszerre multi-target könyvtárak létrehozásához? Erre az egyik válasz (főleg ha szereted a rekurzív definíciókat), hogy a multi-target NuGet package-ek portolható osztálykönyvtárakból (PCL) nem referálhatók be, mert a PCL-ek több platformot támogatnak, így nem választhatják ki egy adott platform assemblyjét a bereferált NuGet package-ből, kivéve ha az is portolható. Tehát a PCL-ek azért szükségesek, hogy más PCL-ek referálhassák őket. Ennek első olvasatra nincs túl sok értelme, de ha nagyobb multi-platform projekten dolgozol, mint pl. egy Xamarin app-on, ami iOS-re és Androidra is fordul, csak a külső app frame-et akarod a konkrét platformra fordítani. Minden mást (a solutionben szereplő összes többi osztálykönyvtárat) platform-függetlennek szeretnél megőrizni. Amennyiben ezek az osztálykönyvtárak egymástól is függnek, három lehetőség van: vagy minden projektet keresztfordítani kell, vagy shared projektet vagy PCL-eket használsz. Mindent keresztfordítani tényleg nem könnyű, mert az MsBuild alapból még nem támogatja ezt (a solutionben nem lehet bereferálni olyan NuGet package-et, amit a solution más projektjéből generáltak). Használhatsz shared
•••
11/22
Bevezetés a .NET Core világába
projekteket, de ez inkább hack, és sok konfigurálást igényel. Így nem marad más hátra, PCL-ekre van szükség. Kérlek, tartsd észben ezt a problémát, pár percen belül visszatérünk rá. Egyéb okok is lehetnek a PCL-ek használatára: 2) te, mint az osztálykönyvtár szerzője, nem szeretnél keresztfordítással vesződni, így inkább egyetlen PCL assemblyt fordítanál; 3) a könyvtárat assemblyként szeretnéd kiadni, és nem NuGet package-ként, így multi-platform single dll-re van szükséged; 4) a NuGet package letöltései méretét csökkenteni szeretnéd. Már láttuk, miért kerültek a PCL-ek bevezetésre. Tehát ismét: szükségünk van rájuk ebben az új project.json alapú rendszerben? Őszintén szólva, nem igazán. Menjünk végig még egyszer a PCL-ek bevezetésének indokain, és értékeljük őket újra ebben az új modellben. 1. A PCL-ekre azért van szükség, hogy be lehessen őket referálni más PCL-ekből – az új modellben ez azt jelentené, hogy van egy project.json alapú, keresztfordított könyvtár, és hozzá akarsz adni egy olyan referenciát, ami egy másik project.json alapú, keresztfordított könyvtárra mutat ugyanabban a solutionben. A jó hír az, hogy a project.json újradefiniálja a referenciák kezelését, és most már más projektet is be lehet referálni, még akkor is, ha az keresztfordított. Így alapjában véve helyi NuGet package-et is be lehet referálni. Ez azt jelenti, hogy ha a solutionben szereplő összes projekt project.json alapú (nem tudom, ez Xamarinban lehetséges-e már, de úgy sejtem, egyelőre nem), a PCL-ek elkerülhetők. 2. Nem akarsz keresztfordítással vesződni – A project.jsonnal ez nagyon egyszerű, így ehhez sincs szükség PCL-ekre. 3. A könyvtárad assemblyként szeretnéd kiadni – A project.json beépített NuGet referencia supporttal rendelkezik, ezért konkrét assembly bereferálása egyre kevésbé szükséges. Így PCL-ekre ehhez sincs szükség. 4. Kisebb NuGet package-eket szeretnél létrehozni. – Nos. Erre még mindig a PCL-ek adnak szép megoldást. Tehát ahogy látható, a könyvtárak alapvetően NuGet package-ként lesznek kiadva. Mivel NuGet package-et bereferálni sokkal természesebb, mint installálni, a NuGEt package-ek installáláshoz kapcsolódó feature-ei (init script, content fájlok, config transformation-ök, stb.) ki lesznek vezetve. (Amúgy is elég sok bajt kevertek.) Így a project.json alapú könyvtárakból nem lehet a generált NuGet package-hez ilyen feature-öket adni, és ha a project.json alapú projektbe NuGet package-et referálunk be, ezek a feature-ök nem lesznek figyelembe véve. Adok-kapok. Összegzésképpen, mikor már minden átkerül a project.json alapú projektrendszerbe (ez akár hamarabb is bekövetkezhet, mint a a .NET Core adaptálása, mert ez normál .NET projektekhez is használható), a PCL-ekre nem igazán lesz szükség, hacsak nem kisebb NuGet package-et szeretnél létrehozni. Sajnos ez még nem a teljes igazság. Létezik egy 5. elem, amit rövidesen felfedezünk. De vonjuk most le a következtetéseket. Mit tudtunk meg eddig? A project.json alapú projektekkel könnyen lehet keresztfordított multi-target NuGet package-eket létrehozni.
•••
12/22
Bevezetés a .NET Core világába
A project.json alapú projektek helyi NuGet package-eket is be tudnak referálni, ami felváltja majd a régi “project reference” koncepciót.
A project.json infrastruktúra olyan könyvtárak fordítására is használható, amelyek nem .NET Core alapúak.
Eddigi következtetések A portolható osztálykönyvtárak (PCL) már tényleg halálra vannak ítélve? Nos, ez a kérdés még nem válaszolható meg, de ahogy látszik, kevésbé van rájuk szükség. De erre a kérdésre a következő részben visszatérünk.
Az assemblyk kiadása és közvetlen bereferálása még mindig megfelelő gyakorlatnak számít? Nem. a NuGet package-ek lesznek a könyvtárak disztribúciós egységei.
A KÖNYVTÁRAD ELÉRHETŐVÉ TÉTELE OLYAN PLATFORMOKRA, AMIKET NEM IS ISMERSZ Ha már hoztál létre olyan NuGet package-et, ami különböző platformokat támogat, tudod, hogy a projektedet az összes specifikus target platform számára le kell fordítanod, és a NuGet package-eden belül olyan platformspecifikus folderbe kell helyezned, mint net451 vagy wpa81. Dönthetsz egy portolható osztálykönyvtár (PCL) fordítása mellett is, de ebben az esetben minden egyes platformot ki kell jelölnöd, amit támogatni szeretnél a PCL projekt létrehozásakor (pl. portable-net451+win81+wpa81). Így mindkét esetben az általad támogatott platformokról explicit listát kell készítened. Ám a platformok száma gyorsan nő, és mivel az IoT (Internet of Things – olyan kis eszközök hálózata, amik adatokat gyűjtenek és cserélnek) egyre népszerűbb, ez a növekedés egyre gyorsabb lesz. Tehát fennáll a lehetőség, hogy a csomagod minden hónapban újra kell fordítani, hogy az új platformok felkerüljenek a listára. Ez nem lenne jó. És tulajdonképpen nem is szükséges. Ezeknek a platformoknak többé-kevésbé ugyanaz az API-ja. Azon platformok esetén, amik olyan eszközön futnak, mint pl. egy telefon, természetesen néhány funkció nem elérhető, de az amúgy benne lévők nagyon hasonlítanak a teljes frameworkben levőkhöz. Tehát az az új ötlet, hogy próbáljunk definiálni valamilyen interface szinteket, úgy, hogy minden framework meg tudja adni, melyik szintet támogatja. A korlátozottabb frameworkök csak egy alacsonyabb szintet fognak támogatni, a teljes framework egy magasabb szintet. Ezek a szintek egymásra épülnek, így ha a framework egy magasabb szintet támogat, azt is jelenti, hogy az alacsonyabbakat is támogatni fogja. Az alacsonyabb szint nem régebbi vagy rosszabb a magasabb szintnél, csak kevesebb standard műveletet támogat. Ezek a szintek most már a .NET Core kezdeményezés részeivé váltak, egy kis problémával. Ugyanis eddig nem találtak nekik jó nevet. Kezdetben “Generations”-nek nevezték őket, jelenlegi nevük .NET Platform Standards. Ami még zavaróbb lehet, hogy kezdetben ezeket a “generációkat” NET Platfrom 5.1, .NET Platfrom 5.2-ként, stb. címkézték. Ezek a számok sokakat megzavartak, mert egyfajta eljövendő .NET verziónak tűntek (most járunk a .NET 4.6.x-nél), de ahogy korábban is írtam, ezek nem verziók, hanem interface kompatibilitási szintek. Jelenlegi megnevezésük .NET Platform Standard 1.0, .NET Platform Standard 1.1, stb. (rövidített formáik ilyenek: netstandard1.2); ez egyértelműbb számozás, bár még mindig nehéz elképzelni, mit fog jelenteni a .NET Platform Standard 2.0, és hogyan fog viszonyulni az 1.x standardekhez.
•••
13/22
Bevezetés a .NET Core világába
Az újabb NuGet verziókkal olyan package is létrehozható, amibe olyan assemblyt csomagolsz, ami egy adott standard szintet implementál. Például ha a könyvtárad netstandard1.2-re fordítod, bármelyik olyan jelenlegi vagy jövőbeni frameworkön használható lesz, ami a .NET Platform Standard 1.2-t vagy ennél magasabb szintet implementál. A Githubon van egy mátrix, ami leírja, melyik jelenlegi frameworkn melyik standardet implementálja, de általában véve elmondható, hogy az 1.0 standardet a .NET 4.5-től kezdve az összes “ismert” framework implementálja, és az 1.4-et csak a .NET 4.6.x és a .NET Core támogatja. Ezek a standard szintek olyan módon vannak definiálva, hogy illeszkednek azokhoz a leggyakoribb platformkombinációkhoz, amik előtte a PCL-ekben használatosak voltak. Pl. a portable-net451+win81+wpa81 szintet használták a netstandard1.2 definiálásához.
De hogyan tudod a könyvtárad lefordítani egy olyan még nem létező, jövőbeni platformra, aminél csak bizonyos APIk specifikációja ismert? A trükk neve Reference Assemblies. A Reference assembly (vagy “contract”) olyan assembly, ami csak class és member szignatúrákat definiál, implementációt viszont nem. Ezek az assemblyk arra használhatók, hogy könyvtárat fordítsanak “hozzájuk”, de nyilvánvalóan arra nem használhatók, hogy az alkalmazást futtassuk (mivel kódot nem tartalmaznak). A különböző standardek reference assembly készleteként állnak rendelkezésre. A reference assembly tulajdonképpen nem új dolog, de eddig nem volt ennyire ismert. Tehát alapjában véve a .NET Platform Standards bevezetésével a PCL új és nagyon erős jelentést kapott. A legtöbb könyvtár számára a kód egy adott standard szintre PCL-ként történő fordítása képezi a legjobb stratégiát. Természetesen a könyvtárnak a lehető legalacsonyabb szintet kell választania (anélkül, hogy a könyvtár céljainak és minőségének tekintetében kompromisszumot kötne), hogy a különböző frameworkök a lehető legszélesebb körét érhesse el. Hogy még jobb legyen, ez nem “mindent vagy semmit” jellegű döntés, amit a könyvtár készítőinek meg kell hozniuk. A NuGet package-be belekerülhet mind standard-alapú és specifikus framework assembly is. (Akár
•••
14/22
Bevezetés a .NET Core világába
saját reference standardjukat is definiálhatják, hogy a “bait and switch” technikát használhassák. Ezek a “lib” helyett a “ref” könyvtárba kerülnek. De erre elég ritkán van szükség.) Ok. Ezek voltak a jó hírek a könyvtár létrehozói számára. Akkor most összegezzük. Mit tudtunk meg eddig? A .NET Platform Standardek olyan API szinteket jelentenek, amiket a különböző frameworkök támogatni tudnak. A szinteket jelenleg 1.0-tól 1.4-ig számozzák, és egymásra épülnek (ha a framework az 1.2-t támogatja, akkor az 1.0-t és az 1.1-t is).
A PCL-ek ezen standardekre is lefordíthatók, és a NuGet is képes az ilyen targetek kezelésre (pl. netstandard1.2).
A standardekre történő fordítás Reference Assemblyk segítségével valósul meg – olyan assemblyken keresztül, amik az adott standard API szintet reprezentálják implementáció nélkül.
A NuGet standard targetek keverhetők specifikus targetekel, akár saját referencia assembly is publikálható.
Eddigi következtetések Igaz, hogy a portolható osztálykönyvtárak már halálra vannak ítélve? Azt hiszem, most már kijelenthetjük, hogy “nem”. Bár sok szempontból kevésbé van rájuk szükség, a .NET Platform Standardekre fordított PCL-ek hatékony eszközei lehetnek a könyvtárfejlesztőknek.
Mi az a .NET 5.4 (vagy dotnet5.4)? Ez a .NET Platfrom Standard 1.3. korábbi neve. A netstandard1.3 váltja fel.
4. ÁLLOMÁS: AHOL KORLÁTOZNI ÉS KONTROLLÁLNI SZERETNÉD, A FRAMEWORK MELYIK RÉSZEI TELEPÜLJENEK AZ APPODDAL Mikor a cross-platform webfejlesztésről beszéltem, említettem, hogy az új infrastruktúra lokális .NET telepítéseket is lehetővé tesz, azaz a telepített alkalmazás nem függ a gépre installált frameworktől. Ez hasznos lehet, mikor ugyanazon a szerveren különböző telepítési ciklusokkal több alkalmazás is hostolva van. Hasonló probléma áll fenn, mikor olyan egyfájlos (single-exe) alkalmazást szeretnél létrehozni, ami az összes dependenciát tartalmazza, és a választott platformra van optimalizálva. Ez a technika a .NET Native, és az egyszerű eszközökre telepített applikációk számára egyre fontosabbá válik. De hogyan kapcsolódik egymáshoz ez a két probléma, azaz a lokális telepítés és az egyfájlos alkalmazás? Fedezzük fel együtt! Az előző cégemnél az ügyfeleink sok kisebb webes alkalmazással rendelkeztek, ezek rendszerint megosztott szerverre voltak feltelepítve. Ez általában jól működött, de időről időre rejtélyes kérdésekkel kellett megharcolnunk. Miután órákig nyomoztunk és az ügyféllel több emailt váltottunk, kiderült, hogy 1) más alkalmazás miatt a gépen a .NET verziót upgrade-elték, 2) volt egy automatikus .NET upgrade, ami megváltoztatta a viselkedést (pl. biztonsági frissítés). A problémát részben az a zűrzavar okozta, hogy néhány .NET verzió képes arra, hogy egymás mellett fusson (pl. a .NET 2.0 és a .NET 4.0), de néhányuk viszont csak implicit upgrade-jei egymásnak (pl. .NET 2.0 és .NET 3.2, vagy .NET 4.0 és .NET 4.5). Ezt nehéz kezelni, még ha ismered is a részleteket. A “legjobb” esetben a telepítési ciklus lelassul, mert más alkalmazások kiegészítő tesztelésére vagy a framework upgrade-ek más beszállítókkal való szinkronizálására van szükség.
•••
15/22
Bevezetés a .NET Core világába
Amennyiben a saját szerveredről van szó, és a rajta levő alkalmazásokat teljes mértékben átlátod úgy, ahogy a mi ügyfelünk esetében történt, szerencsés helyzetben vagy. De ha felhő alapú szolgáltató vagy (mint a Microsoft Azure), a megosztott szerverek működtetése még több problémát okozhat. A .NET Core egy teljesen új kódbázis kisebb (és fókuszáltabb) függőséggel az operációs rendszertől, a csomagok amúgy is a nuget.org-ról jönnek, így könnyűnek tűnik a webes alkalmazások és a teljes framework együttes telepítésének kivitelezése. Igen, könnyű, és ez az az út, amit választani fogunk, ám ezzel a megközelítéssel két probléma is van. 1. A teljes framework még mindig túl nagy. Az app teljes frameworkkel történő feltelepítése túl sok időt és sávszélességet elvenne. 2. Bár a gépre installált framework upgrade-je általában véve problematikus, ha fontos biztonsági frissítésről beszélünk, ezen javítások elvégzésének felelősségét áthelyezni az egyes beszállítókra szintén problémákat okozna. Így a frameworkkel együtt telepített webalkalmazásokra a megoldás összetettebb, mint gondolnánk, de általában ha az alkalmazás .NET Core-ra fordul, működik a dolog (az ASP.NET Core sima .NET-re is tud fordulni, emlékszel?) Természetesen még sok olyan helyzet van, mikor az „installált” .NET framework jobb, így ez csak egy telepítési opció, amit választani lehet. A buildrendszer (.NET CLI) képes azokat a könyvtárakat megkeresni, amikre tényleg szükséged van, és csak azokat csomagolni az alkalmazás mellé. Ahogy láttuk, a .NET Core sokkal modulárisabb, mint a normál .NET Framework, így lehetőség van a megfelelő dependenciák kiválasztására. Egyet kivéve… ez a reflection.
A REFLECTION TÖRTÉNET Reflctionnel bármit be lehetett tölteni a .NET Frameworkből magára az assemblyre vagy az osztályra mutató explicit referencia nélkül. A reflection az API standardizálásnál is problémás, mivel az interface definíciók kikerülhetők, és a non-standard részek elérhetők. Természetesen sok olyan eset van, mikor a reflection tényleg szükséges, ám számos olyan alkalmazás létezik, amiknek enélkül is remekül kell működniük. Ezen érvekből kiindulva a .NET Core úgy döntött, a reflectiont külön modulba választja le, ez a System.Reflection, hogy az alkalmazás és a könyvtárak fejlesztői expliciten jelölhessék, szükségük van-e reflectionre vagy sem. Ez jól hangzik, de ezzel a változással körkörös dependencia alakulna ki: a System.Object osztály (a runtime-ban van) rendelkezik egy GetType() metódussal, ami visszaad egy Type példányt. A Type osztály metódusai, mint pl. a GetMethod(), MethodInfo-t adnak vissza, ami viszont a System.Reflection-ben van. Tehát a runtime-nak és a System.Reflectionnek kölcsönösen kellene függniük egymástól. Ennek feloldására a a Type osztály referencia- és definíciós aspektusát a .NET Core-ban szétválasztották (ez talán a legnagyobb breaking change): a Type osztály csak a referencia aspektusával foglalkozik, így alapjában véve csak a típus nevét tartalmazza, és van egy új típus a System.Reflection.dll-ben, ez a TypeInfo, ami számos olyan reflectionhöz kapcsolódó metódust tartalmaz, ami korábban a Type osztályon volt. A System.Reflection.dll olyan extension metódust is definiál a Type-on, ez a GetTypeInfo(), ami visszaadja a TypeInfo példányt a típusra. Így az olyan metódushívásokat, mint pl. a myType.GetMethod(“foo”), módosítani kell myType.GetTypeInfo().GetMethod(“foo”)-ra. Hogy az API a .NET Core-ral és a normál .NET Frameworkökkel egyaránt kompatibilis maradjon, ez az új osztály és extension metódus a normál .NET Framework 4.5-be és más jól ismert .NET frameworkökbe is belekerült.
•••
16/22
Bevezetés a .NET Core világába
Ez logikusan hangzik? Talán igen, de ez tényleg attól függ, hány alkalmazás tud tényleg élni reflection nélkül. Sok olyan frameworköt és könyvtárat használunk, amik a háttérben reflectiont használnak. Például mivel a .NET-ben nincs beépített megoldás az AOP támogatására (aspektus-orientált programozás – cross-cutting funkcionalitás hozzáadása a kódbázishoz, általában attribútumok által) számos framework (web, adatkezelés, loggolás, biztonság, stb.) reflectiont használ. Ez fájdalmas breaking change? Bizonyára igen. A .NET Core első release-e ezzel az új, szeparált reflection koncepcióval nemsokára kijön, de a Microsoft már bejelentette, hogy erősen fontolgatják a reflection (és más egyéb API-k) visszahelyezését, hogy a meglévő alkalmazások számára a migrációs folyamatot megkönnyítsék. A szeparáció bizonyos értelemben megmarad, így az (új) alkalmazások számára, amiknek olyan platformon kell futniuk, ahol a reflection nem elérhető, még mindig lesz lehetőség konzisztens kisebb API használatára. Ez a lépés egyrészt érthető, másrészt, főleg mert a .NET Core 1.0 már a breaking change-dzsel jön ki, késleltetheti a .NET Core szélesebb körű adaptációját, és további zavart okozhat.
.NET NATIVE Ahogy említettem, van egy másik ötlet, ez a .NET Native, melynek célja az alkalmazás és a framework egyfajta egyedi, target platformra és teljesítményre optimalizált fájlba való becsomagolása. Annak kiválasztásához, a framework mely részeinek kell benne lenniük a natívra fordított bináris kódban, ugyanazokat a kérdéseket és problémákat kell felvetni, mint amiket a webes alkalmazás telepítésénél megbeszéltünk. A natívra történő fordításnál viszont sok más problémát is meg kell oldani. A nyilvánvaló hasonlóságok ellenére a .NET Native a .NET Core-tól teljesen függetlenül indult, és jelenleg főleg csak a Universal Appok használják, amikre a .NET Core még nem elérhető. Viszont a .NET CLI bevezetésével a natívra történő fordítás opciója a .NET Core applikációk közé is bekerült. (Ne feledd, ez jelenleg a webes és console alkalmazásokat jelent.) Miért? Azt hiszem, az egyik ok az volt, hogy ki akarták próbálni, ezt a technológiát a felhasználók hogyan fogadják. Még ha a natívra történő fordításban nem is olyan sok webes projekt lesz érdekelt, lesz néhány olyan, aki a .NET Core team részére hasznos feedbacket tud küldeni. A másik ok az a technológia, amit eddig még nem említettünk, de amiről egyre többet fogunk hallani a .NETes világban: a containerek. A containerek olyan virtualizált operációs rendszerek, amik az alkalmazást összes függőségével együtt úgy be tudják csomagolni, hogy “bármely” gazda operációs rendszerre egyszerűen telepíthető legyen. Talán már hallottál a Docker containerről, ez egyike a legnépszerűbb nyílt forráskódú containerkezelő tooloknak. A containerek megkönnyíthetik a telepítést, mert az alkalmazás egy jól meghatározott containerbe telepíthető, anélkül, hogy ismernénk a végső gazdagép részleteit és beállításait. A containerek kiválóan illeszkednek a framework izolációs koncepcióhoz, amit a .NET Core-ban már láttunk; natív fordítással viszont mindez könnyebben megy, és a containerek mérete is kisebb lesz. (2016 májusban a native fordítási opció ideiglenesen kikerült a release-ből. A cikk olvasásakor remélhetőleg újra kipróbálható már.)
•••
17/22
Bevezetés a .NET Core világába
Mit tudtunk meg eddig? A .NET Core alkalmazások magával a frameworkkel együtt telepíthetők, hogy támogatni tudják a megosztott szerver architektúrákat, beleértve a container-alapú telepítést is.
A függőségek alapján csak azok a package-ek lesznek feltelepítve, amelyek az alkalmazáshoz szükségesek, annak érdekében, hogy a telepítő csomag méretét korlátozni lehessen.
A biztonsági javítócsomagok központilag akár az ilyen fajta telepítésekhez is szállíthatók (bár a részleteket nem ismerem).
A reflection API el lett különítve, hogy a statikus függőségi analízis a “hétköznapi” helyzetekben könnyebb legyen. Ám a tervek szerint ez a migráció megkönnyítése érdekében vissza fog térni.
A Type osztályt felosztották. A Type immár csak referencia (a nevet tartalmazza), és van egy új osztály, ennek neve TypeInfo, ami tartalmazza a reflectionhöz tartozó API-t. A System.Reflection egy GetTypeInfo() extension metódust is definiál a Type osztályon. Ez a .NET 4.5-ben is elérhető, hogy a kompatibilitás kódszinten megmaradjon.
A .NET Core alkalmazások egyetlen fájlba fordíthatók (hasonlóan a .NET Native-hez Universal Appokhoz). (Jelenleg ideiglenesen kikerült a release-ből.)
Eddigi következtetések Mi az a .NET Native, és hogyan kapcsolódik a .NET Core-hoz? A .NET Native packaging opció a Universal Appokhoz, független a .NET Core-tól, de hasonló problémákat old meg. A .NET Native-ben használt technológia alapján most a .NET Core alkalmazások is fordíthatók egyetlen fájlba. (Jelenleg ideiglenesen kikerült a release-ből.)
•••
Mi a netcore és a netcore50 target framework NuGet-ben, és hogyan kapcsolódnak a .NET Core-hoz? Ezek a Universal Appok targetei, a megtévesztő név ellenére nem kapcsolódnak a .NET Core-hoz.
18/22
Bevezetés a .NET Core világába
ÖSSZEGZÉS Ezen hosszú és talán kimerítő utazás során megpróbáltuk felfedezni a .NET Core-t, valamint más egyéb kapcsolódó technológiát és ötletet. Felfedező utunkat különböző felhasználási esettanulmányok segítségével tettük meg.
Láttuk, hogyan lehetne esetleg a .NET Core-ral cross-platform desktop alkalmazást létrehozni (jelenleg nem támogatott), és hogyan kapcsolódik a .NET Core a Mono projekthez. Aztán felfedeztük az ASP.NET Core-ral és a .NET Core-ral történő cross-platform webes alkalmazások fejlesztésének új lehetőségeit. Ez az a történet, ami az egész .NET Core kezdeményezést elindította. Láttuk itt a .NET Core és az ASP.NET Core trükkös viszonyát, és azt, hogyan működnek az új forráskódként telepített és futás közben fordított webes alkalmazások a .NET CLI toolok használatával (dotnet). Ezután fejest ugrottunk a cross-platform könyvtár fejlesztők napi problémáiba, és arra jutottunk, hogy az ASP.NET Core-ra létrehozott, project.json alapú projektrendszer jól működik a NuGet package-ként kiadott cross-platform könyvtárak létrehozása során is. A lokális NuGet package bereferálhatóságának köszönhetően ez a módszer jól működik privát osztálykönyvtárakkal is.
•••
19/22
Bevezetés a .NET Core világába
A cross-platform könyvtár fejlesztésének kihívásaiból kiindulva felderítettük, hogyan változik a portolható osztálykönyvtárak (PCL) szerepe a .NET Core-ral. A különböző .NET Framework variánsok növekvő számával a frameworkök széles skálájának támogatása egyre nehezebbé válik. A .NET Platform Standards jól meghatározott API rétegek készlete. A különböző frameworkök képesek implementálni ezen rétegek valamelyikét, és a könyvtárak fejlesztői le tudják fordítani a kódjukat az egyik ilyen standardre portolható osztálykönyvtárként. Végezetül, láttunk két esetet, amikor is a framework összecsomagolása az alkalmazással hasznosnak bizonyult. Az első ilyen, mikor a webes alkalmazást megosztott szerverre telepítünk fel. Ezt a forgatókönyvet a .NET Core is támogatja. A második, mikor az alkalmazást egy adott eszközre optimalizált, egyetlen fájlba kell lefordítani. Ezt a forgatókönyvet a .NET Native támogatja Universal Appokhoz, ill. a .NET Core a .NET CLI tooljainak segítségével. Ez a két technológia egymástól független, de a fő megoldások és kihívások ugyanazok. Ezen utazás során egész listányi tényt gyűjtöttünk össze, és a témához kapcsolódó számos kérdésre próbáltunk választ adni. Utalásként lásd ezeket egy blokkban lent. Köszönöm, hogy velem tartottál ezen az úton! Mit tudtunk meg az utunk során? A .NET Core egy teljesen új .NET-szerű framework, ami vékony cross-platform runtime-ból (CoreCLR) és olyan (cross-platform és platform-független) könyvtárakból (CoreFX) áll, amik NuGet packageekként tölthetők le a NuGet.org-on keresztül.
Sem a Mono, sem a normál .NET framework nem tud a .NET Core-on “futni”, még csak a CoreCLR-en sem.
A felhasználó nézőpontjából (pl. az API), a .NET Core és a normál .NET framework nagyon hasonlít egymáshoz, de a .NET Core-nak kevesebb funkciót támogat, pl. még nincs gazdag UI könyvtár. Ez a normál .NET Framework és a Mono privilégiuma marad a közelebbi jövőben.
Az ASP.NET Core az ASP.NET teljesen új implementációja. Inkább a modern webes alkalmazások szükségleteire fókuszál (pl. egyszerűbb HTTP request pipeline), és nem függ közvetlenül az IIS-től.
Az ASP.NET mind a .NET Core és a normál .NET Framework alatt egyaránt fut.
Az ASP.NET Core nem implementálja az ASP.NET összes funkcióját (vagy mert elavultak, vagy mert több idő szükséges a befejezésükhöz). Így lesznek olyan scenariók, amikhez időnként a régi ASP.NET frameworkre lesz szükség.
A .NET CLI (.NET Command Line Tools) forráskódként telepített, igény szerint fordított, cross-platform alkalmazásokhoz való futtatási környezet. A funkcionalitásokat olyan parancsokon keresztül vezeti ki, amik a console-ból a dotnet mycommand-dal hívhatók meg. A parancsok, akárcsak az alkalmazás (=projekt) többi része, a project.json fájlban vannak meghatározva.
A DNU (.NET Development Utility), a DNX (.NET Execution Environment) és a DNVM (.NET Version Manager) az RC1 tooljai voltak projektek futtatásához, buildeléséhez és konfigurálásához. A .NET CLI felváltotta ezeket a toolokat, így ezekre már nincs szükség.
A project.json nemsokára elavulttá fog válni, és funkcióit az MsBuild veszi át (ld. bejelentés).
•••
20/22
Bevezetés a .NET Core világába
A project.json alapú projektekkel könnyen lehet keresztfordított multi-target NuGet package-eket létrehozni.
A project.json alapú projektek helyi NuGet package-eket is be tudnak referálni, ami felváltja majd a régi “project reference” koncepciót.
A project.json infrastruktúra olyan könyvtárak fordítására is használható, amelyek nem .NET Core alapúak.
A .NET Platform Standardek olyan API szinteket jelentenek, amiket a különböző frameworkök támogatni tudnak. A szinteket jelenleg 1.0-tól 1.4-ig számozzák, és egymásra épülnek (ha a framework az 1.2-t támogatja, akkor az 1.0-t és az 1.1-t is).
A PCL-ek ezen standardekre is lefordíthatók, és a NuGet is képes az ilyen targetek kezelésre (pl. netstandard1.2).
A standardekre történő fordítás Reference Assemblyk segítségével valósul meg – olyan assemblyken keresztül, amik az adott standard API szintet reprezentálják implementáció nélkül.
A NuGet standard targetek keverhetők specifikus targetekel, akár saját referencia assembly is publikálható.
A .NET Core alkalmazások magával a frameworkkel együtt telepíthetők, hogy támogatni tudják a megosztott szerver architektúrákat, beleértve a container-alapú telepítést is.
A függőségek alapján csak azok a package-ek lesznek feltelepítve, amelyek az alkalmazáshoz szükségesek, annak érdekében, hogy a telepítő csomag méretét korlátozni lehessen.
A biztonsági javítócsomagok központilag akár az ilyen fajta telepítésekhez is szállíthatók (bár a részleteket nem ismerem).
A reflection API el lett különítve, hogy a statikus függőségi analízis a “hétköznapi” helyzetekben könnyebb legyen. Ám a tervek szerint ez a migráció megkönnyítése érdekében vissza fog térni.
A Type osztályt felosztották. A Type immár csak referencia (a nevet tartalmazza), és van egy új osztály, ennek neve TypeInfo, ami tartalmazza a reflectionhöz tartozó API-t. A System.Reflection egy GetTypeInfo() extension metódust is definiál a Type osztályon. Ez a .NET 4.5-ben is elérhető, hogy a kompatibilitás kódszinten megmaradjon.
A .NET Core alkalmazások egyetlen fájlba fordíthatók (hasonlóan a .NET Native-hez Universal Appokhoz). (Jelenleg ideiglenesen kikerült a release-ből.)
A kérdések, amikre választ kaptunk Mi a .NET Core, és miért hívták először .NET 5-nek? Mert ez egy olyan új .NET (-szerű) framework, ami esetleg majd helyettesítheti a normál .NET Frameworköt, ami jelenleg a 4.6.2 verziónál tart.
•••
Miért nevezték át utána .NET Core 1.0-ra? Mert rájöttek, hogy a közeljövőben a .NET Core nem lesz képes a normál .NET Frameworköt helyettesíteni, hanem ezek párhuzamosan, egymás mellett fognak fejlődni.
21/22
Bevezetés a .NET Core világába
Miért nevezték az ASP.NET Core-t először ASP.NET 5-nek vagy ASP.NET vNextnek? Mert ez egy új ASP.NET framework, ami egyszer esetleg helyettesítheti a normál ASP.NET frameworköt.
Majd miért nevezték át ASP.NET Core 1.0-nak? Mert rájöttek, hogy a közeljövőben az ASP.NET Core nem lesz képes a normál ASP.NET Framework helyettesítésére, hanem párhuzamosan fognak fejlődni.
Miért látok net461-t és netcoreapp1.0-t (vagy dnx451-et és dnxcore50-et VS2015 Update 1-gyel) target frameworkökként, ha egy új ASP.NET Core projektet hozok létre? Mert egyaránt tud futni.NET Coreon (netcoreapp1.0) és a normál .NET Frameworkön (net461).
Miért van benne a “Core” a névben, ha a normál .NETFramework alatt is fut? Hát igen. Jó kérdés.
A DNX ASP.NET specifikus? Igen is és nem is. Maga a DNX egy tool, amit az ASP.NET Core-hoz fejlesztettek ki, de console alkalmazások futtatásához is használható. Viszont a forráskódként való telepítési stílus legvalószínűbben csak a webes alkalmazások körében lesz népszerű.
A .NET CLI ASP.NET specifikus? Nem. Részint ez az oka annak, miért váltotta le a DNX-et.
A .NET CLI .NET Core specifikus? Nem. A .NET CLI toolok a normál .NET Frameworkre is tudnak projekteket buildelni és futtatni.
Az assemblyk kiadása és közvetlen bereferálása még mindig megfelelő gyakorlatnak számít? Nem. a NuGet package-ek lesznek a könyvtárak disztribúciós egységei.
A portolható osztálykönyvtárak (PCL) már tényleg halálra vannak ítélve? Nem. Bár sok szempontból kevésbé van rájuk szükség, a .NET Platform Standardekre fordított PCL-ek hatékony eszközei lehetnek a könyvtárfejlesztőknek.
Mi az a .NET 5.4 (vagy dotnet5.4)? Ez a .NET Platfrom Standard 1.3. korábbi neve. A netstandard1.3 váltja fel.
Mi az a .NET Native, és hogyan kapcsolódik a .NET Core-hoz? A .NET Native packaging opció a Universal Appokhoz, független a .NET Core-tól, de hasonló problémákat old meg. A .NET Native-ben használt technológia alapján most a .NET Core alkalmazások is fordíthatók egyetlen fájlba. (Jelenleg ideiglenesen kikerült a release-ből.)
Mi a netcore és a netcore50 target framework NuGet-ben, és hogyan kapcsolódnak a .NET Core-hoz? Ezek a Universal Appok targetei, a megtévesztő név ellenére nem kapcsolódnak a .NET Core-hoz.
•••
22/22