.NET LINUX ALATT
Konstantinusz Kft. © 2009
Tartalomjegyzék 1. Bevezető............................................................................................................................. 3 2. A probléma felvetése..........................................................................................................5 3. .NET Keretrendszer............................................................................................................6 3.1. Mi is a .NET pontosan?............................................................................................................6 3.2. Milyen szolgáltatásokat nyújt?.................................................................................................6 3.3. Hogyan épül fel?.......................................................................................................................8
4. Egy alternatív implementáció: A Mono keretrendszer......................................................10 5. .NET alkalmazások portolása Mono alá...........................................................................10 5. ASP.NET Linuxon apache mod mono.............................................................................14 6. Összegzés:........................................................................................................................16
1. Bevezető Nagy alkalmazások fejlesztésekor nagyon fontos szempont, hogy minél hatékonyabban, a lehető legrövidebb idő alatt álljon elő a szoftver. Az alkalmazás fejlesztésekor sok más dolog mellett ismerni kell, figyelembe kell venni azt a környezetet, amelyben az alkalmazása futni fog.
A környezet egyik legfontosabb jellemzője az operációs rendszer, ezen belül is az API. A programozónak ismernie kell a megfelelő API-t, hogy használni tudja azt. Az operációs rendszer funkciói, szolgáltatásai ezen szabványos illesztőfelületen keresztül érhetők el az alkalmazások számára (pl.: fájlrendszer kezelése, eszközkezelés, megszakítások szálkezelés, és hibakezelés, grafikus felhasználói felület stb.). Ezek a különböző operációs rendszereken természetesen különböznek (a .NET ezen szempontból egy új API-nak is tekinthető, ugyanis egy .NET környezetben a programozónak semmilyen más API-t nem kell ismernie).
Ahhoz, hogy az alkalmazás széles körben használható legyen, biztosítani kell a platform függetlenséget, ami a különböző platformok miatt több különböző kódbázist igényel. Hatékonyság szempontjából azonban jó lenne, ha elég lenne egy közös kódbázist fenntartani az alkalmazáshoz . A programkódot elég lenne egyszer lefordítani, és futtatható Linux, Windows, OSX és más UNIX rendszereken. Ugyanis az újraírás sok időbe és erőforrásba kerül, valamint a fejlesztők ismeretei nem használhatók maradéktalanul más platformokon, ezért ez a megoldás nem hatékony. A .NET használatával erre tudunk megoldást találni, ugyanis a .NET-ben megírt programok egy virtuális gép utasításkészletére fordulnak le, ami operációs rendszer független, elég ezt a futtató környezetet a különböző platformokra implementálni és a kód máris hordozható.
A környezet másik fontos összetevője a hardver, ami szintén sok fejfájást tud okozni: ha a fordító natív kódra fordít, akkor optimalizálja egy bizonyos architektúra utasításkészletéhez, ami x86 vagy x64 (ezen belül persze szintén problémák vannak, hiszen a különböző gyártók másmás utasításkészlettel szerelik fel a processzoraikat, így ha a natív fordító statikusan lefordít valamit x86 alá, az sem Intel sem Amd platformon nem lesz optimális, hanem egy köztes megoldás lesz). A legfőbb probléma felhasználói szempontból az, hogyha a felhasználó átáll x86-ról x64-es architektúrára, jogosan várja el, hogy a régi program módosítás nélkül fusson az új hardveren.
Elvileg a 64 bites operációs rendszerek képesek futtatni a régi 32 bites programokat virtuális módban, de ezekkel a gyakorlatban szintén sok probléma van (pl. tömb indexek, Linuxon problémás 64 biten) Ez azonban még ha működik is, nem optimális.
A .NET és a JIT előnye egyértelmű, ha az operációs rendszer x64-es. Ilyenkor a JIT ugyan azt a binárist x64-re fordítja, így semmit nem kell tenni azért, hogy x86-on x86-ra, x64-en x64-re optimalizált kódot kapjunk. A .NET-es IL 90%-át már a futtatás előtt lefordítja a JIT, méghozzá adott processzorra optimalizált natív kódra, a többit pedig menet közben egyszer, utána ezt cacheli, tehát sok esetben épphogy gyorsabb lesz a futás, pláne, a mai többmagos processzorok esetében.
Ezektől szintén megkímélhetjük magunkat a ..NET használatával, ugyanis a ..NET-es programok egy virtuális mikroprocesszor, virtuális gépi kódú utasításkészletére van fordítva, és ezt hajtja végre a CLR-t.
Tehát a .NET igazi előnye, hogy a fejlesztésre magára lehet koncentrálni, nem kell platform vagy gép- specifikus kódot írnunk.
Összegzés • Az alkalmazás operációs rendszer független lesz • Független lesz az architektúrától • Mivel a legelterjedtebb nyelveket támogatja (több mint 40 et!) nem kell új nyelvet tanulni. • Garbage Collector • Eleve adott egy rendkívül széles szolgáltatás-rendszer (BCL), ami radikálisan csökkenti a fejlesztési időt
2. A probléma felvetése Az alapkoncepció egyszerű: egy .NET-ben megírt program minden platformon változtatás nélkül futtatható. Sajnos, a gyakorlatban ez nem így működik. A legfőbb problémát az jelenti, hogy mivel a .NET (a Javaval ellentétben) gyártóspecifikus,ezért az implementációi eltérnek az egyes operációs rendszereken (az igazsághoz az is hozzátartozik, hogy a java sem teljesen hordozható).
A Microsoft .NET Framework jelen pillanatban csak és kizárólag Microsoft Windows operációs rendszerek alatt érhető el. Ugyanakkor a szabványosítás után a CLI specifikáció nyilvános és bárki számára elérhető lett, ezen ismeretek birtokában pedig több független csapat vagy cég is létrehozta a saját CLI implementációját, bár eddig még nem sikerült teljes mértékben reprodukálni az eredetit. Ezt a célt nehezíti, hogy a Microsoft időközben számos a specifikációban nem szereplő változtatást végzett a keretrendszeren.
Alternatív megoldások
DotGNU A DotGNU a GNU projekt része, amelynek célja egy ingyenes és nyílt alternatívát nyújtani a Microsoft implementáció helyett. Ez a projekt – szemben a Mono-val – nem a Microsoft BCL-el való kompatibilitást helyezi el térbe, hanem az eredeti szabvány pontos és tökéletes implementációjának a létrehozását. A DotGNU saját CLI megvalósításának a Portable .NET nevet adta. A jegyzet írásának idején a projekt leállni látszik. Mono A Mono implementációja az ECMA szabványokon, a C# programozási nyelven, és a CLI-n alapul. A C#-on felül több más nyelvet is támogat, így a programok készülhetnek C++, Python, Boo, Java nyelveken is. A Mono magában foglalja a Windows.Forms, ADO.NET, ASP.NET könyvtárak implementációját. Az alap könyvtárak mellett támogatja a jellemzően UNIX-os rendszerek által kínált szolgáltatásokat, például GTK#, Mozilla, Gnome könyvtárak. A Mono szinte minden operációs rendszeren használható, létezik Windows változata is. A Mono egy jó alternatíva, de nem tökéletes, ugyanis sok dolog egyszerűen nincs implementálva benne. Sok eszköz implementációja eltér a .NET-es változatától, és rengeteg „bug” van benne, aminek köszönhetően rendkívül instabil (pl.: a Windows Forms implementációja nagyon sok „bug”-ot tartalmaz, köszönhetően annak, hogy a Microsoft nem nyitotta meg a kódját, így a fejlesztők csak találgatnak, hogy mit hogyan kéne). Sajnos, az eddigi tapasztalatok tükrében a teljes hordozhatóság nem valósítható meg tökéletesen, ezért az elkészült alkalmazást portolni kell a más platformokra.
3. .NET Keretrendszer 3.1. Mi is a .NET pontosan? A .NET-re pontos definíció nem létezik, inkább csak körül írni szokták. Íme a Wikipédián található definíció: "A Microsoft által készített .NET keretrendszer (a .NET Framework) gyors alkalmazásfejlesztést (RAD), platformfüggetlenséget és hálózati átlátszóságot támogató szoftverfejlesztői platform. A keretrendszert a korábbi platform a COM leváltására szánták. Eredetileg a .NET kifejezés nem kizárólagosan
a
fejlesztői
környezetet
jelentette,
de
fejlesztőeszközök,
szoftverek
sőt
hardvereszközök összességét is. Az évek során a kép kitisztult, így mostanra a .NET alatt a keretrendszert értjük."
3.2. Milyen szolgáltatásokat nyújt? Átjárhatóság: A régi és új alkalmazások közti együttműködés megkönnyítéséhez a .NET átjárhatóságot biztosít a COM és a .NET komponensek között, be tudja csomagolni a COM komponenseket és fordítva. Minden .NET osztály használható COM objektumként, a Framework támogatja COM objektumokat is .NET osztályokként importálhatunk. Közös Futtatórendszer:
Minden .NET-ben megírt program, a nyelvtől függetlenül a Common Intermediate Language-re (CIL) fordul, és a végrehajtását a Közös nyelvi futtatórendszer vezérli. Ennek köszönhetően egységesen valósul meg a memóriakezelés, kivételkezelés stb..(Nagy előny, hogy a szóban forgó virtuális gépi kódú nyelv típusos, ezért a programkód futtatása közben a memória-hozzáféréseket ellenőrizni lehet – így meggátolható a helytelen, hibás viselkedés. Másrészt az utasítások végrehajtása előtt ellenőrizni lehet a jogosultságot is.)
Egyszerűbb fejlesztés: A Base Class Library (BCL) olyan osztályokat biztosít, amely rengeteg közös szolgáltatást fed el: • egységes alaptípusok, • Az egyszerű típusok is osztályok automatikus konverzióval (boxing, unboxing) • kollekciótípusok • generikusok • standard I/O • fájlok kezelés • XML dokumentumok kezelése • meglévő Windows API elfedése • szálkezelés kivételkezelés • stb.
A .NET keretrendszer tartalmaz olyan eszközöket amik az elkészült alkalmazás telepítése során abban segítenek, hogy az új szoftver ne befolyásolja a már korábban telepített programokat, ne okozzon mellékhatásokat, és biztosítsa a biztonsági követelményeket. Megvalósítható a nyelvek közti átjárhatóság, más nyelvekben definiált osztályok, típusok használata, öröklődés akár nyelvek között is.
Biztonságos programozás: A felépítésből fakadóan kivéd olyan sebezhetőségeket, mint a „buffer” túlcsordulás, amiket sok rosszindulatú szoftver ki tud használni. Ezen felül közös biztonsági modellt biztosít minden .Net-es alkalmazás számára.
Garbage Collector:
Kihasználhatjuk az automatikus memória-menedzselés szolgáltatásait (Garbage Collector).
3.3. Hogyan épül fel?
CLI A Common Language Infrastructure a különböző programozási nyelven írt programok futtatására szolgáló alrendszere a .NET keretrendszernek. A megjelenése előtt minden nyelvnek saját futtató modulja volt, hogy a lefordított alkalmazás működhessen. A közös futtathatóságot úgy érték el, hogy minden nyelvet egy úgynevezett CIL (Common Intermediate Language) vagy MSIL (Microsoft Intermediate Language) nyelvre fordítanak le. A CLI egy osztálykönyvtárat és egy virtuális gépet használ. Az osztálykönyvtár jelen esetben a Base Class Library, a virtuális gép pedig a CLR a Common Language Runtime. Itt is látható a Java-féle koncepció, hiszen ők is egy virtuális gépet (Java Runtime Enviroment/ Java Virtual Machine) használnak a lefordított java bytecode futtatásához.
CLR • Common Type System (CTS): egységes típusrendszer, mely azokat a .NET típusokat definiálja, amelyek alapjai a CLR működésének. Garantálja azt, hogy összes implementált nyelv képes legyen futni .NET platform alatt, aminek az alapja a közös típusrendszer. Tehát, minden nyelv innen veszi a típusokat, csak más alias-ként hivatkozunk rájuk (pl.: int C# alatt int, Basic alatt Integer). A CTS felölős ezen kívül a típusok átjárhatóságáért (konvertálás). Minden, ami a CTS-ben van: objektum! Így minden a System.Object-ig visszavezethető. • Common Language Specification (CLS): általános szabályokat fogalmaz meg, melyeket a .NET nyelvnek be kell tartaniuk. Ennek köszönhető a nyelvfüggetlenség, így a .NET alkalmazásainkat bármilyen nyelven is írjuk az eredmény elméletben ugyanaz. • Just-In-Time Compiler (JIT): ez az IL kódról natív kódra fordító rendszer. • Virtual Execution System (VES): virtuális futtató rendszer, mely a CIL parancsot végrehajtja, kezeli memóriát, stb.
Összességben a CLR az alábbi 3 szolgáltatást nyújtja nekünk: • kódellenőrzés (code verification), • kódbiztonság (code access security) • hulladékgyűjtés (garbage collection). Ez az alapja a menedzselt kódnak.
4. Egy alternatív implementáció: A Mono keretrendszer A Mono egy nyílt forráskódú keretrendszer, mely stabil alapja lehet a kifejlesztendő szoftvertermékeknek. A Microsoft .NET keretrendszerétől eltérően a Mono szinte minden operációs rendszeren használható. Így a .NET képességei más operációs rendszereken is elérhetőek a Mono segítségével. A programkódot elég egyszer lefordítani, és futtatható Linux, Windows, OSX és más UNIX rendszereken. A Mono implementációja az ECMA szabványokon, a C# programozási nyelven, és a Common Language Infrastructure-en alapul. A C#-on felül több más nyelvet is támogat, így a programok készülhetnek C++, Python, Boo, Java nyelveken is. A Mono-nak sikerült kompatibilis maradnia a .NET-el. Ez magában foglalja a Windows.Forms, ADO.NET, ASP.NET könyvtárakat. Az alap könyvtárak mellett támogatja a jellemzően UNIX-os rendszerek által kínált szolgáltatásokat, például GTK#, Mozilla, Gnome könyvtárak. A Mono mögött a Novell áll, ami garanciát jelent a folyamatos fejlesztésre. Több nagyobb projektben is sikeresen vezették be a Mono-ra építkező alkalmazásokat. Jelenleg több – főleg Linuxon elterjedt – alkalmazás is bizonyítja, hogy a Mono egy kiváló rendszer. A keretrendszerrel együtt elérhető egy kiváló fejlesztőeszköz, a Monodevelop.
5. .NET alkalmazások portolása Mono alá
A Mono egy alternatív megoldást nyújt a .NET helyett, viszonylag nagy mértékben kompatibilis vele. A Mono fejlesztői szerint a meglévő .NET-es alkalmazások 40% a módosítás nélkül fut Mono alatt, 35% kis módosítással, a maradék pedig néhány hónapos munkával portolható. A teljes hordozhatóság azonban nem lehetséges a következő problémák miatt:
Általános problémák: • Bizonyos eszközök, (osztályok, osztályok bizonyos metódusai) nincsenek implementálva a mono-ban, ekkor a keretrendszer NotImplemented exceptiont dob. • Bizonyos eszközök, metódusok mono alatt máshogy működnek, különböző hibákat okoznak • Az operációs rendszer specifikus dolgoknak nem biztos, hogy minden esetben létezik megfelelő alternatívája az adott platformon
Nyilvánvaló tehát, hogy a teljes hordozhatóság nem valósítható meg, szükséges az alkalmazás portolása, illetve hangolása Mono alá.(Lehet olyan eset hogy a módosított alkalmazás fut .Net alatt is.) Felmerül tehát az igény, hogy esetleg már az alkalmazás fejlesztése közben figyelemmel lehessen kísérni, hogy hogyan fog működni Mono alatt. Erre a célra a Mono alkotói elkészítették Mono Tools for Visual Studio-t, amely beépül a stúdióba, és segítséget nyújt az alkalmazás Linux platformom való teszteléséhez. A legfontosabb funkciója, hogy kiértékeli a .Net kódot és megmutatja ahol esetleg kompatibilitási gondok adódhatnak a két környezet közt, valamint az API hívásokat, hogy van-e megfelelője a célplatformon. Lehetőség nyílik az integrált tesztelésre is, azaz a kód. Mono/Linuxon történő lefuttatására és másik gép meghívásával. További szolgáltatása, hogy telepítőcsomagot készít Suse linux alá.
Mint mindig itt is adódnak azonban problémák. Annak ellenére, hogy nagyon jól kidolgozott eszközről van szó, mégsem tudja az éles tesztet helyettesíteni, legfeljebb a súlyosabb problémákról ad tájékoztatást így jó kiindulópontot jelent a portolásnál.
Konkrét problémák: A Mono Tools teszteléshez használt alkalmazás .NET/Windows környezetben lett írva, Windows Forms-t használ, MySql adatbázishoz csatlakozik ehhez a MySql által kiadott .NET Provider-t használja. Az Migration Analyser első körben a következő problémákat jelezte: • A következő eszköz még nincs implementálva Mono-ban, ezért a keretrendszer NotImplementedException-t dob ennek az eszköznek a használatakor. Warning
2
The method void SmtpClient.set_UseDefaultCredentials(bool) could
potentially throw a NotImplementedException in Mono. Message
1
MonoTodo: void SmtpClient.set_UseDefaultCredentials(bool)
Reason: no DefaultCredential support in Mono
Problémák, amiket az Analyser nem jelezett: • Ezen problémák orvosolása után jött a futtatás a Windows alá telepített Mono környezetben, ahol az alkalmazás el is indult, ám amikor csatlakozásra került volna a sor kivétel keletkezett hosszú StackTrace-el: Unhandled Exception: System.ArgumentException: Keyword not
supported.
Parameter name: ;charset at MySql.Data.MySqlClient.MySqlConnectionStringBuilder.GetKey (System.String key) [0x00000] .... A problémát a MySql provider okozza, ugyanis a Mono-s változat más formában várja a connection string-t • .NET-es provider: string ConnectionString = "Server=localhost;" + "Database=myDatabas;" + "User ID=username;" + "Password=myPassword;" + "Pooling=false;"; • Mono-s provider: string ConnectionString = "server=localhost;" + "database=myDatabas;" + "user is=username;" + "pwd=myPassword;" + "pooling=false;"; A probléma orvosolása után, csatlakozott az adatbázishoz onnan meg is kapta az adatokat, de a MainForm on elhelyezett egyik DataGridview a következő kivételt dobta, az alábbi metódus hívására: void rc_ReaderListUpdated(object sender, EventArgs e) { _readerListGridView.Columns[1].HeaderText = _loc.tr("Name"); _readerListGridView.Columns[2].HeaderText = _loc.tr("Address"); _readerListGridView.Columns[3].HeaderText = _loc.tr("Born"); _readerListGridView.Columns[4].HeaderText = _loc.tr("Mother name"); } Unhandled Exception: System.ArgumentOutOfRangeException: Index is or more than or equal to the list count. Parameter name: index 0...
less than 0
Ezt a problémát a Mono Windows.Forms implementációjának hibája okozza, „Bug report” is készült
róla,
ám
javításra
még
nem
került,
a
Window-os
változatban.
Átvittem a módosított alkalmazást Kubuntu 9.04 alá, Mono 2.0 környezetbe, és az alkalmazás elindult. A hiba tehát tényleg a DataGridview hibája okozza, de ez a „bug” a Linuxos Mono-n ki lett javítva. Ezek után az alkalmazás minden funkciója működött. A UI elemek máshogy néznek ki, máshol helyezkednek el. Ezek a hibák néhány óra munkával javíthatók. A Windows Forms implementáció tesztelése során néhány „bug”-t még sikerült reprodukálni, amik jelen pillanatban Kubuntu 9.04 alatt problémát jelentenek: • A DataGridviewhez lehet olyan oszlopot adni, amely képet tartalmaz. Ez a funkció nem működik Ubuntu alatt. • A DataGridview-ba történő kattintáskor hozzáad egy üres sort, ekkor a sor minden oszlopában 'null' érték jelenik meg, ami még csak esztétikai hiba, de ha megismétlem akkor a következő kivétellel leáll az alkalmazás: "Unhandled Exception: System.IndexOutOfRangeException: list position" • A DataGrivoewba kattintva ha az első sorba nyomok egy lefele nyilat új sort szúr be, ha ezek után felfelé nyilat akkor: "Unhandled Exception: System.IndexOutOfRangeException: list position" kivétellel leáll az alkalmazás • Opensuse alatt ha dinamikusan adok hozzá egy menühöz menüpontokat kivétellel leáll az alkalmazás, Kubuntu alatt a hiba nem jelentkezik
5. ASP.NET Linuxon apache mod mono
A web, mint platform
Manapság egyre nagyobb igény van olyan egyedi szoftveres megoldásokra, amelyek a normál asztali alkalmazások teljesítményét képesek nyújtani, és bárki könnyedén használhatja őket anélkül, hogy telepítenie kellene. Ide tartoznak azok a Gadget-k és Widget-k is, melyekkel a felhasználó munkaasztalszerűvé varázsolhatja az általa gyakran látogatott oldalakat, illetve közös felületről kezelheti, menedzselheti hálózati alkalmazásait. Vagy ide tartoznak a vállalatirányítási rendszerek, árajánlat kérő rendszerek, adminisztrációs rendszerek. A web mint platform sokkal jobban megvalósítja a hordozhatóságot, mivel a kezdetektől jobban rá volt kényszerítve a szabványok betartására (persze ez is csak bizonyos szintig igaz). Az egyetemi képzés tananyaga, csak felszínesen érinti a webet, kevés hangsúly kerül a rá, mint platformra. A webes cégek jelentős energiát fektetnek a friss diplomások ezen hiányosságainak pótlására. A cégek részéről igény lenne tehát arra, hogy minél kevesebb munka befektetésével, munkára lehessen fogni a frissen végzetteket. Az ASP.NET használatára egyszerűbb áttérni a Windowsos alkalmazásfejlesztőknek, hiszen ezen technológiával készülő honlapok komponenseken (ASP.NET Web Forms) alapulnak, ahogy a Windows-os programok is, az alkalmazás fejlesztése pedig gyakorlatilag a különböző komponensek eseményvezérlőinek kifejtésével történik. Rendkívül széles területre kiterjedő osztálygyűjtemény segíti a programozó munkáját, amely jelentős részét egy képzett .NET fejlesztő ismeri, sőt a C# és a Visual Basic ismerete is rendkívül jól hasznosítható, ugyanis az ASP.NET támogatja ezeket.
Problémák A fejlesztéshez használható a Monodevelop Linux alatt, sajnos ez azonban nem 100%-os megoldás hiszen a visual designer gyerekcipőben jár, komoly munkára nem használható. A másik probléma a web hosting. Ma Magyarországon nagyon kevés szolgáltató foglalkozik ASP.NET honlap hostinggal, míg PHP-s szolgáltatókból bőséges választék áll rendelkezésünkre. Ebből következően az ASP.NET honlapok fenntartása drágább. Amennyiben saját szerveren akarjuk tárolni adatainkat, akkor figyelembe kell venni azt is, hogy a PHP-nál jellemző Linux-Apache platformon nem futtathatók ASP.NET alkalmazások. Egy megoldást jelenthet az Apache mod_asp kiegészítője, azonban még gyerekcipőben jár, ráadásul a fejlesztése is nagyon akadozik.
Egy pár probléma: • jelen pillanatban csak 2.0-ás .NET-t támogat azt sem tökéletesen • csak a C# nyelvet támogatja • rengeteg idő vesz igénybe a meglévő kódok portolása
6. Összegzés:
A portolásban segítséget jelent a Mono Tools for Visual Studio, de sajnos ez sem helyettesíti az éles tesztet. A teljes hordozhatóság továbbra is csak ígéret, a gyakorlat legalábbis ezt mutatja. A Windows Forms implementáció tele van bugokkal, megoldást jelenthez a GTK# használata, ami Windowsos környezetben csak a GTK+ telepítésével használható, így a hordozhatóság nagyon megkérdőjelezhető. Az ASP.NET alkalmazások jól működnek különböző platformok, ám a hosting csak Windowsos szerveren történhet, ami nagyon drága.