Migrace aplikace na .NET Core

Tomáš Herceg       17.05.2015       C#, ASP.NET/IIS, Reflexe, .NET       12781 zobrazení

Včera jsem se rozhodl v praxi vyzkoušet, jak snadné nebo složité je zmigrovat kód z .NETu 4.5 na .NET Core – vzal jsem Redwood a vytvořil jsem větev dotnetcore, která obsahuje (zatím ještě nezkompilovatelnou) verzi.

Redwood jsem psal s ohledem na to, že tu migraci budu v budoucnu provádět a tím pádem jsem se snažil vyvarovat použití věcí, o kterých jsem věděl, že v novém .NET Core nebudou (zejména cokoliv ze System.Web atd.).

I tak jsem ale narazil na pár věcí, které bude potřeba upravit či řešit jinak – stále mi tam visí 19 kompilačních chyb a to jsem řešil zatím jen projekt Framework, neřešil jsem jeho použití v ASP.NET aplikaci (i když to už nebude tak složité).

Každopádně pokud chcete migraci provádět, dejte si pozor na následující (tento seznam rozhodně není úplný – je v něm jen to, na co jsem při migraci Redwoodu narazil):

 

Runtime T4 šablony

T4 šablony spouštěné za běhu (více v článku Používáme T4 šablony). Tyto šablony fungují tak, že z nich Visual Studio vygeneruje třídu, která obsahuje vše, co nadeklarujete v šabloně uvnitř bloků ohraničených <#+  #>, a funkci TransformText, která celou transformaci spustí.
Bohužel to, co VS standardně generuje, má závislosti na namespace System.CodeDom, který v .NET Core není a nebude (nahradil ho Roslyn).

Navíc Visual Studio ani v projektu pro nový framework T4 šablony nepodporuje a nevygeneruje z nich patřičný výstup. Vzhledem k tomu, že jsem šablony potřeboval, a vzhledem k tomu, že pro automatizaci procesů při vývoji se dá využít Grunt, napsal jsem do něj (v javascriptu – grr!!) vlastní task grunt-runtime-t4-template-task, který poštvete na T4 šablonu a ona z ní vygeneruje patřičnou C# třídu. Tato třída nemá závislosti na CodeDomu, jediné omezení je, že nepodporuje metody jako PushIndent, PopIndent a pár dalších věcí – nicméně ten základ, že vytvoříte instanci šablony, naplníte ji daty a zavoláte TransformText, ten pochopitelně funguje.

Vyzkoušel jsem si při tom Visual Studio Code a na jednodušší věci to není úplně špatné, dokonce se mi povedlo donutit ho, aby mi ten grunt task spustil a uměl v něm debugovat, což mě velmi potěšilo.

 

RESX soubory

Další podobnou libůstkou, kterou ještě vyřešenou nemám, je kompilace RESX souborů. Člověk byl zvyklý, že v projektu vytvořil soubor MyResources.resx, což na pozadí vygenerovalo třídu MyResources, která měla jednotlivé položky zpřístupněné jako readonly properties, takže stačilo napsat MyResources.MyErrorMessage a vrátilo to danou položku v aktuálním jazyce.

Nic takového v .NET Core opět není, takže jsem napsal ještě grunt task grunt-resx-compile-task, který tohle také řeší – vygeneruje třídu, která je zkompilovatelná v .NET Core.

 

NuGet téměř balíčky pro každý namespace

.NET Core dramaticky změnil rozdělení jednotlivých tříd do assemblies. Vše je velmi modulární, takže třeba System.IO, System.Reflection, System.Collections apod. jsou separátní knihovny, které se distribuují pomocí NuGetu.

Má to svůj smysl, protože framework není jeden monolitický balík, který se updatuje jednou za 2 roky, nicméně aby to bylo použitelné, bylo by krásné, kdyby člověk ve chvíli, kdy ve Visual Studiu napíše název nějaké třídy, aby mu to zobrazilo nejen namespace, ale i ze kterého NuGet balíčku pochází a hlavně aby to snadno umožnilo dotáhnout balíčky, které chybí (o což se VS do jisté míry snaží, ale zatím to moc nefunguje).

V souboru package.json pak bohužel IntelliSense nenabízí všechny balíčky, které by měla, takže člověk píše a hádá naslepo, jak by se daný balíček mohl jmenovat.

Velmi užitečná služba je http://packagesearch.azurewebsites.net/, kde zadáte název třídy nebo metody a ono vám to najde balíčky, které tuto metodu obsahují. Je také dobré se podívat na složku https://github.com/dotnet/corefx/tree/master/src, kde je velmi dobře vidět, na jaké balíčky byl .NET rozdělen – v zásadě platí, že co složka, to NuGet balíček.

 

AppDomain a Assembly

Vzhledem k tomu, že Redwood je samá reflection, narazil jsem na mnoho kompilačních chyb. Autoři .NET Core totiž udělali jednu drobnou změnu, a to zeštíhlení třídy System.Type. Spousta vlastností a metod, které tam byly, jsou nyní dostupné ne přímo ze System.Type, ale musíte na ní zavolat extension metodu GetTypeInfo, jejíž výsledek teprve obsahuje to, co potřebujete (např. vlastnosti Assembly, IsValueType atd.). Takže jsem to musel asi na 150 místech měnit. To byl ovšem ten menší problém.

Zbylo mi tam 15 kompilačních chyb, se kterými se budu muset vypořádat, jelikož .NET Core změnil některé základní principy. Třída Assembly má pouze metodu Load, která umí načíst assembly dle názvu. Není tam žádná funkce, která by uměla načíst assembly ze streamu nebo z pole bajtů – pokud ano, tak se jmenuje jinak a nepovedlo se mi ji zatím najít. Oblíbené a často používané funkce Assembly.GetExecutingAssembly chybí.

Podobně je na tom třída AppDomain – pokud jste ve starém .NETu chtěli zjistit seznam assemblies, které jsou ve vaší appdoméně načtené, zavolali jste AppDomain.CurrentDomain.GetAssemblies. Tato funkce zde není, takže budu muset najít jiný způsob, jak se s tím vypořádat.

 

OWIN

Nedávno Microsoft začal humbuk kolem OWINu, a tak jsem Redwood naimplementoval na Owinu, nicméně teď jsem jej musel upravit tak, aby nepoužíval OWIN, ale nový ASP.NET runtime. Prakticky je rozdíl jen v pojmenování tříd (IApplicationBuilder místo IAppBuidler, RequestDelegate místo IOwinMiddleware apod.) a vše je v jiných namespacech, principy naštěstí zůstaly stejné, takže se jednalo jen o relativně snadné úpravy.

 

Každopádně udržovat dvě verze frameworku pro nový a starý .NET možná nebude tak jednoduché – budu muset zjistit, jestli je to reálně možné. Projekt ve VS to sice podporuje, nicméně vzhledem k tomu, že framework používá věci z nového ASP.NET, nebude to zřejmě tak snadné udělat, abych měl jeden kód pro obě platformy. Uvidíme.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

Příspěvky zaslané pod tento článek se neobjeví hned, ale až po schválení administrátorem.

Nuget

Resharper už to umí řešit. http://i.snag.gy/soNzT.jpg

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Load assembly ze streamu

Assembly ze streamu lze načíst nějak takhle:

//IAssemblyLoadContextAccessor loaderAccessor
//Stream assemblyData 

var loader = loaderAccessor.GetLoadContext(typeof(MyClass).GetTypeInfo().Assembly);
var assembly = loader.LoadStream(assemblyData, null);

kde loaderAccessor typu Microsoft.Framework.Runtime.IAssemblyLoadContextAccessor si je potřeba nechat resolvnout z DI kontejneru a assemblyData je stream assembly. MyClass je nějaká třída v našem projektu (určuje kontext pro načtení dalších assembly).

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Na to už jsem taky přišel, potíž je v tom, že v Roslynu plánují zrušit jednu funkci, kterou používám a která umožňuje vytáhnout metadata z assembly, takže to, na co potřebuju načíst assembly ze streamu, stejně budu dělat jinak - pátrám dál, co s tím.

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Assembly.Load

To je zajímavé, že v coreclr mscorlib ta metoda Assembly.Load(byte[]) je. https://github.com/dotnet/coreclr/blob/m.... A GetExecutingAssembly je tam taky.

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Aha, tak v CoreCLR je, ale v CoreFX ne. Zajímavé.

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Co jsem to pochopil, tak CoreFX mscorlib vůbec neobsahuje. To je věc CoreCLR. A netuším proč se to nechce zkompilovat při použití nějaké té metody, když CoreCLR i normální velký CLR je podporuje. Nemohlo bz to být něco s WinRT? Protože všechny hacky jak to obejít co jsem našel řešily tyhle metro aplikace.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

Příspěvky zaslané pod tento článek se neobjeví hned, ale až po schválení administrátorem.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback