2007. június havi bejegyzések

Excel export ASP.NET-ből

Gyakori feladat, hogy a webalkalmazásaink adatbázisából valamilyen használható formátumban kell adatokat exportálnunk. Egy átlagos felhasználó számára a relációs adatok használható formátuma az Excel. Íme néhány módszer Excel fájl előállítására ASP.NET-ből:

1. OLE DB

Ennél a módszernél kihasználjuk, hogy az Excel OLE DB provideren keresztül elérhető, a connection string valami ilyesmi lesz:

    private string _connectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=MyFile.xls;Extended Properties=""Excel 8.0;""";

Miután rányitottunk OleDbConnectionnel, az OleDbCommand osztály segítségével szórhatjuk a SELECT-eket, INSERT-eket, DELETE-eket és UPDATE-eket. Minden egyes sheet táblaként érhető el.

Ennek a megközelítésnek az előnye, hogy előre elkészíthetünk és beformázhatunk egy Excel fájlt, a beleírt adatok nem rontják el a formázást. Persze ne teljes formázásra tessék gondolni, tipikusan felesleges sheetek kiírtása, magyarázó szövegek mellékelése, fejléc értelmes formában történő megadása, néhány formázás stb.

A nagy hátránya, hogy ha egy általános DataSet -> Excel export osztályt akarunk készíteni, akkor meg fog gyűlni a bajunk az SQL utasítások összefűzésével, mert persze tárolt eljárásokról szó se lehet. Gyakorlatilag INSERT utasításokat kell majd összeállítanunk a DataSet minden egyes sorához, ahol leginkább a speciális karakterek escape-elésére és az egyes mezőtípusokra kell figyelni. Sajnos az ilyen általános osztályoknál tapasztalataink szerint a dátum például sztringként szokott megérkezni az Excelbe, aposztróffal prefixelve. Puff neki, csak nyomtatni lehet, formázni nem.

2. Excel objektum modell

Van az Excelnek egy gyönyörű objektum modellje, ami elérhető, ha referenciát adunk a Microsoft Excel 11.0 Object Library COM komponensre, majd bejúzingoljuk a Microsoft.Office.Interop.Excel névteret. Tessék vele nyugodtan játszani, egy darabig még akár élmény is lehet az Excel.Workbook és az Excel.Worksheet osztályok használata és teljesen jól is fog működni a fejlesztői gépünkön.

Ezzel a megoldással két igen nagy probléma van, ha ASP.NET-ből akarjuk használni:

  • A szerverre Excelt kell telepíteni, amihez licenc kell, telepíteni kell, frissíteni kell stb.
  • Az Excelt nem szerver oldali környezetbe tervezték, ezért nem is működik jól a szerveren. Tipikusan nem szereti, ha egyszerre több szálon matatják az objektumait és bizony könnyen ki lehet akasztani, arról nem is beszélve, hogy zabálja a memóriát.

Ergó ezt a megközelítést tessék elfelejteni ASP.NET környezetben. Pont.

3. XLSX fájl előállítása

Ha megengedhetjük magunknak, hogy Excel 2007-re optimalizálunk és megkövetelhetjük a szerveren a .NET Framework 3.0-t, akkor gyárthatunk XLSX fájlokat közvetlenül kódból. Ehhez tömöríteni kell tudni és nyers XML-t írni. A tömörítéshez még használhatjuk a WindowsBase.dll-ben lévő Packaging API-t (System.IO.Packaging névtér), de az Excel specifikus XML gyártáshoz nem marad más, mint a System.Xml névtér. Ez majdnem semmi, meg kell ismernünk a teljes Excel sémát.

Ez a megoldás jól működik szerver oldalon és Excel sem kell hozzá. Bár a Microsoft ezt nagyon favorizálja, nem fehér embernek való feladat, ráadásul tényleg csak Excel 2007-tel működik (bár van Compatibility Pack a 2003-hoz).

4. HTML előállítása

Ha nincs szükségünk minden Excel funkcióra, akkor trükközhetünk egy kicsit: kihasználhatjuk, hogy az Excel meg tud nyitni HTML fájlokat és felismeri bennük a táblázatokat. Gyárthatunk tehát szerver oldalon egyszerű HTML táblázatot, mert ha azt kliens oldalon Excellel nyitjuk meg, az eredmény majdnem ugyanaz, mintha közvetlenül Excel fájlt gyártottunk volna. Az alábbi kód pont erre szolgál:

    StringWriter sw = new StringWriter();
    HtmlTextWriter wr = new HtmlTextWriter( sw );

    wr.RenderBeginTag( HtmlTextWriterTag.H1 );
    wr.Write( "Ez itt a cím" );
    wr.RenderEndTag();

    GridView grid = new GridView();
    grid.DataSource = this.GetData();
    grid.DataBind();
    grid.HeaderStyle.Font.Bold = true;
    grid.RenderControl( wr );

    this.Response.Clear();
    this.Response.ContentType = "application/vnd.ms-excel";
    this.Response.Write( sw.ToString() );
    this.Response.End();

A megoldás előnye, hogy aránylag egyszerű, nem kell Excel a szerverre, sőt még a típusok is jól mennek át. A hátrány, hogy ez nyilván egy trükközés, nem tudunk minden Excel funkciót elérni, és az Excelben megnyitott HTML oldalban nem látszanak a cellarácsok.

Íme tehát négy megoldás, mindegyiknek vannak előnyei és hátrányai, lehet választani!

 

Technorati tags: ,

Helyi? Biztonságos?

A nagyobb osztálykönyvtárak hátránya, hogy nincs élő ember, aki elejétől a végéig képes lenne átlátni. Ezért aztán születnek olyan kódrészletek, melyek lényegesen egyszerűbben is megírhatóak lennének.

Az egyik gyakori eset annak lekérdezése, hogy SSL-en keresztül nézik-e az oldalt. A brute force megoldás valami ilyesmi:

    if( this.Request.Url.ToString().StartsWith( "https" ) )...

Badarság a System.Uri-t Stringgé alakítani, mikor az helyből szét tudja szedni az URL-t, tehát akár ezt is írhatjuk:

    if( this.Request.Url.Scheme == Uri.UriSchemeHttps )...

A legegyszerűbb azonban talán mégis ez:

    if( this.Request.IsSecureConnection )...

Meg lehet nézni Reflectorban, a FormsAuthentication osztály SetAuthCookie metódusa is ezt használja:

    if( !current.Request.IsSecureConnection && RequireSSL )
    {
        throw new HttpException( SR.GetString( "Connection_not_secure_creating_secure_cookie" ) );
    }

 

Amennyiben csak a HTTPS a kérdés, még alig van különbség a fenti sztring buheráláshoz szükséges karakterek száma és a legolvashatóbb megoldás karakterszáma között. Ámde a helyzet sokkal zűrösebb, ha azt kell vizsgálnunk, hogy helyi kapcsolaton keresztül nézik az oldalt, vagy távolról. A balga módszer nekiesni az URL-nek és megkeresni benne a localhostot. Ez még String.IndexOf hívással is szörnyű, de láttam már olyat, aki biztosra akart menni és ezért előbb a ":" mentén, aztán a "/" mentén felsplittelte az URL sztringet, majd a keletkező tömbök közül a megfelelőre nézett sztring egyezést. Téptem a hajam….

A kérdés eldöntéséhez elméletben meg kell vizsgálni, hogy az alábbi esetek közül igaz-e valamelyik:

  • A cél domain localhost.
  • A cél IP cím 127.0.0.1.
  • A cél IP cím a gép valamelyik IP címe.

Mivel a localhost címe 127.0.0.1, ezért ha IP cím alapján nézzük, akkor csak az a kérdés, hogy a kérés a 127.0.0.1-re, vagy a gép valamelyik címére érkezett-e.

Természetesen erre is van rövid megoldás a HttpRequest osztályban:

    if( this.Request.IsLocal )...

Elfogadhatóan rövid, nem? Nézzük meg Reflectorral, hogyan működik:

    public bool IsLocal
    {
        get
        {
            string userHostAddress = this.UserHostAddress;
            if( string.IsNullOrEmpty( userHostAddress ) )
            {
                return false;
            }
            return ( ( ( userHostAddress == "127.0.0.1" ) || 
( userHostAddress == "::1" ) ) ||
( userHostAddress == this.LocalAddress ) ); } }

Ez valóban jól működik az összes fenti esetre, de persze csak akkor, ha az ember sejti, hogy van ilyen tulajdonság, amit csak le kell kérdezni. Nincs mese, a legtöbb hasonló probléma esetén úgy kell hozzáállni a .NET Frameworkhöz, hogy van itt x ezer darab osztály, jó sokan írták és jó sok helyen használják, tutira megoldották már azt, amivel én csak most szembesültem. Ez nálam általában beválik, ha a megoldás nem az MSDN-ből, akkor a Google-ből kiderül.

 

Technorati tags:

Linkblog: SQL Server 2005 cikkek

Meg kell hagyni, SQL Server 2005 témakörben vannak nagyon jó cikkek nem csak blogokban, hanem az MSDN oldalain is, ami többek között annak köszönhető, hogy olyanok írják őket, mint Kimberly "SQL Goddess" Tripp. Aki esetleg nem ismerné, ezen a címen találhat sok whitepapert, továbbá a teljesség kedvéért idemásolom az SQL Server 2005-tel foglalkozó microsoft.com/sql oldal, az MSDN és a TechNet cikkeket összegyűjtő oldalak címeit is.

 

Technorati tags: ,

Doksizás

Mindenki utál doksit írni, nem kicsit, nagyon. A legtöbb, amire egy fejlesztőt rá lehet venni, az némi (nem több) XML komment írása a C# forráskódba, azt is csak azért, mert az IntelliSense megjeleníti. Sokszor találjuk magunkat olyan projektben, ahol a megrendelő forráskód szinten szeretné újrafelhasználni a munkánk eredményét, amihez legjobban egy MSDN-szerű CHM formátumú dokumentációt tudna használni.

Korábban erre a célra az NDocot használtuk, van vele azonban néhány probléma. A legfontosabb, hogy a projekt elaludt és bár teljesen nyílt forráskódú és sokan használják, senki nem veszi a fáradtságot, hogy érdemben besegítsen. Ez azért probléma, mert az utolsó változat még nem támogatja tökéletesen a .NET 2.0-át és azon belül leginkább a generikus típusokat, hanem hibával elszáll. Van belőle egy trükközött 1.3.1 verzió, ami legalább továbbmegy, de az sem tökéletes. Ráadásul nálam éppen Windows Beasta alatt valami single threaded apartment hibával elhal a konzolos változat, így nem tudjuk automatikusan beépíteni a fordítási folyamatba.

Hogy mit használ a Microsoft azt sokáig homály fedte, egy idő óta azonban elérhető a Sandcastle project előzetes változata, három napja a júniusi CTP. Szerintem aki ezt először meglátja mind azt mondja, hogy milyen szép egyszerű dizájn, de a fene se akarja használni. Pedig ezzel, pontosabban még a márciusi CTP-vel készült az Orcas béta dokumentációja is. Ami rém gusztustalanná teszi az egészet az az, hogy lényegében XSLT transzformációk sorozataként áll elő minden tartalom. Ugyan kapunk néhány XSLT fájlt a letöltéskor, de ha valamit módosítani akarunk (pl. copyright vagy preliminary szöveg), akkor az XML-be kell belemászni. A megfelelőbe. 

Ráadásul nem egy transzformációt kell végeznünk, hanem például CHM fájl előállításához egy egész sorozatot. Nálam például az alábbi szkript build.cmd prototype DLLnevekiterjesztésnélkül módon indítva CHM kimenetet ad, ha telepítve van a HTML Help Workshop, abban van ugyanis a HTML Help Compiler (hhc.exe):

    @echo off
    @echo - PATH modositasa...
    set DXROOT=C:Program FilesSandCastle
    set PATH=c:WINDOWSMicrosoft.NETFrameworkv2.0.50727;%DXROOT%ProductionTools;C:Program FilesHTML Help Workshop;C:Program FilesMicrosoft Help 2.0 SDK;%PATH%

    rem Alapertelmezes szerint comments.xml fajlt keres a Sandcastle, modositani kell a configban *.xml-re!
    @echo - Bemeneti fajlok masolasa
    copy ..bindebug*.dll . /Y >nul
    copy ..bindebug*.xml . /Y >nul

    @echo - Output mappa torlese...
    if exist Output rmdir Output /s /q  >nul

    @echo - MRefBuilder futtatasa...
    MRefBuilder %2.dll /out:reflection.org >nul

    @echo - Az eredmeny atalakitasa...
    XslTransform /xsl:"%DXROOT%ProductionTransformsApplyPrototypeDocModel.xsl" reflection.org /xsl:"%DXROOT%ProductionTransformsAddGuidFilenames.xsl" /out:reflection.xml  >nul

    @echo - Topic manifest keszitese...
    XslTransform /xsl:"%DXROOT%ProductionTransformsReflectionToManifest.xsl"  reflection.xml /out:manifest.xml  >nul

    @echo - Kimeneti mappastruktura letrehozasa...
    call "%DXROOT%Presentation%1copyOutput.bat"  >nul

    @echo - BuildAssembler futtatasa (ez nagyon sokaig tart, turelem)...
    BuildAssembler /config:"%DXROOT%Presentation%1configurationsandcastle.config" manifest.xml  >nul

    @echo - HTML Help project fajl letrehozasa...
    XslTransform /xsl:"%DXROOT%ProductionTransformsReflectionToChmProject.xsl" reflection.xml /out:Output%2.hhp /arg:project=%2  >nul

    @echo - TOC generalasa...
    XslTransform /xsl:"%DXROOT%ProductionTransformscreatePrototypetoc.xsl" reflection.xml /out:toc.xml  >nul

    @echo - HTML Help project informacio letrehozasa...
    XslTransform /xsl:"%DXROOT%ProductionTransformsTocToChmContents.xsl" toc.xml /out:Output%2.hhc  >nul
    XslTransform /xsl:"%DXROOT%ProductionTransformsReflectionToChmIndex.xsl" reflection.xml /out:Output%2.hhk  >nul

    @echo - CHM eloallitasa...
    hhc Output%2.hhp  >nul

    @echo - CHM fajl masolasa
    copy Output%2.chm . >nul

    @echo - Atmeneti fajlok torlese...
    del manifest.xml  >nul
    del reflection.org  >nul
    del reflection.xml  >nul
    del toc.xml  >nul
    del *.dll  >nul
    del *.xml  >nul
    rmdir IntelliSense /s /q
    rmdir Output /s /q

    @echo Kesz.

Ha valakinek nem tetszik a prototype stílusú kimenetet, választhat vs2005 és már vsorcas közül is. Ez utóbbi neve ne tévesszen meg senkit, nem azzal fog készülni a Visual Studio 2008 dokumentációja.

Van ugyan néhány GUI, de ennek a projektnek az ereje mégis abban rejlik, hogy be tudjuk építeni a fordítási folyamatunkba. Ha így teszünk, akkor készüljünk fel rá, hogy nagyon lassú, sok nagyságreddel lassabb az NDocnál, legalábbis az én gépemen. A GUI-k közül a fantáziadús SandcastleGUI nevű projekt előnye, hogy grafikus felületen megmondhatjuk, hogy mit hogyan szeretnénk lefordítani és az így létrejött egyedi formátumú projekt fájlt GUI nélkül, parancssori környezetben is tudjuk használni, így ez végülis automatizálható.

Akinek ezzel sikerült kedvet csinálni, a következő címeken talál bővebb információkat:

Más mit használ?

 

Technorati tags: , ,

Workflow tulajdonságainak kiolvasása

Gyakori kérdés, hogy egy adott workflow példány belső állapotát, mezőit, tulajdonságait hogyan lehet kiolvasni? A rövid válasz, hogy egyszerűen sehogy:

  • Egy futó workflow esetén az ember a WorkflowInstance osztály környékén próbálkozik, amin keresztül legfeljebb az InstanceId lehet megszerezni. Futó workflow esetén az igazi megoldás az lehet, ha kommunikálunk a folyamattal, azaz a Queuing- vagy az ExternalDataExchangeServicen-en keresztül üzenetet küldünk neki.
  • Egy már lefutott workflow példány esetén már nincs más lehetőségünk, mint a tracking service használata.

Az utóbbi az érdekesebb és kevésbé dokumentált eset. A cél tehát egy SimpleWorkflow típusú folyamat Result tulajdonságának utólagos kiolvasása.

Ehhez szükségünk lesz a tracking szolgáltatásra, használjuk a beépített SqlTrackingService-t, hozzuk létre az adatbázisát például WorkflowTrackingStore néven és adjuk hozzá a runtime-hoz:

    const string connectionString = 
@"Initial Catalog=WorkflowTrackingStore;Data Source=.SqlExpress;Integrated Security=SSPI;"; SqlTrackingService trackingService = new SqlTrackingService( connectionString ); runtime.AddService( trackingService );

A workflow futtatásakor nem kell semmi extrát tennünk, a tracking naplóz. Csakhogy nem azt naplózza, ami nekünk kell, hanem amiről azt hiszi, hogy nekünk kell! A tracking profile szolgál arra, hogy meghatározzuk, mire van szükségünk. Ezt megtehetjük objektum modell segítségével (használva a System.Workflow.Runtime.Tracking.TrackingProfile) osztályt, vagy deklaratívan egy XML segítségével. XML-t senki sem szeret kézzel írni (minden ellenkező híreszteléssel szemben az XML nem arra való, hogy homo sapiensek olvassák), a profil összeállításához használjuk a WF SDK példák között elérhető Tracking Profile Designert (közvetlenül letölthető a WF közösségi oldalról is).

Néhány tipp a Tracking Profile Designer használatához:

  • Ne felejtsük el módosítani a tracking adatbázisunkra mutató connection stringet a .config állományban.
  • Másoljuk az exe mellé a workflow-nkat tartalmazó lefordított szerelvényt.
  • A profil erősen típusosan hivatkozik a naplózandó workflow típusára, ami egyben a workflow-t tartalmazó szerelvényre is erősen típusos hivatkozást jelent. Ha nem akarjuk minden fordítás után módosítani a profilt, akkor a workflow AssemblyInfo.cs fájljában adjunk fix és ne csillagos verziószámot az AssemblyVersion attribútumban.
  • Ne csak adatbázisba mentsük el a létrehozott profilt, hanem archiváljuk magunknak XML-be is.

A profilban workflow, activity és felhasználói eseményeket tudunk meghatározni. Ahhoz, hogy egy adott tulajdonság értékét naplózza a rendszer, ún. data tracking extractot kell definiálnunk. Erre szolgál a TrackingExtract ősosztály, amiből a WorkflowDataTrackingExtract és az ActivityDataTrackingExtract származik. Biztos én bénáztam, de akárhogy kattintgattam a profile designerben, nekem nem sikerült workflow extractot létrehozni, csak activity extractot. Annyi baj legyen, a szekvenciális workflow végülis egy szép nagy sequence activity.

Nekem ez lett a profil:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<TrackingProfile xmlns="http://schemas.microsoft.com/winfx/2006/workflow/trackingprofile" version="1.0.0">
    <TrackPoints>
        <ActivityTrackPoint>
            <MatchingLocations>
                <ActivityTrackingLocation>
                    <Activity>
                        <Type>MyApp.SimpleWorkflow, MyApp, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null</Type>
                        <MatchDerivedTypes>false</MatchDerivedTypes>
                    </Activity>
                    <ExecutionStatusEvents>
                        <ExecutionStatus>Closed</ExecutionStatus>
                    </ExecutionStatusEvents>
                </ActivityTrackingLocation>
            </MatchingLocations>
            <Extracts>
                <ActivityDataTrackingExtract>
                    <Member>Result</Member>
                </ActivityDataTrackingExtract>
            </Extracts>
        </ActivityTrackPoint>
    </TrackPoints>
</TrackingProfile>

Emberi nyelvre fordítva: a SimpleWorkflow típusú activity (!) Closed eseményekor kérjük a Result tulajdonság naplózását. És semmi több! Ha tehát valaki később csak a lefutott workflow példányokat szeretné felolvasni vagy további tracking információkra van szüksége, az kénytelen lesz kiegészíteni a profilt még azokkal is.

Az összekattintgatott profilt mentsük el az adatbázisba. Akit érdekel, hogy mi történik a háttérben, az nézze meg a TrackingProfile táblát vagy az UpdateProfile tárolt eljárást.

Megvan tehát a workflow és a profil, ha most futtatjuk a folyamatot, akkor az adatbázisba be kell kerülnie a naplózandó adatoknak. Érdemes bekukkantani a TrackingDataItem táblába, ha mindent jól csináltunk, ott lesz.

Nem maradt más hátra, le kell kérdeznünk a tracking adatbázist, mégpedig az objektum modell SqlTrackingQuery osztályának segítségével:

    const string connectionString = 
@"Initial Catalog=WorkflowTrackingStore;Data Source=.SqlExpress;Integrated Security=SSPI;"; SqlTrackingQuery query = new SqlTrackingQuery( connectionString );

Csak azokat a workflow példányokat kérjük, amik SimpleWorkflow típusúak:

    SqlTrackingQueryOptions options = new SqlTrackingQueryOptions();
    options.WorkflowType = typeof( MyApp.SimpleWorkflow ); // Egyben szerelvény és verzió hivatkozás is!

Na itt kell észnél lenni, mert ha itt megszokásból megadjuk, hogy csak a Completed állapotú példányokra vagyunk kiváncsiak, de ennek a ténynek a naplózását nem kértük a profilban, akkor nem lesz eredményünk. Kérjük vissza a feltételnek megfelelő példányokat és ha nem akarunk sokat debuggolni, írassuk ki, hogy lett-e eredmény:

    IList<SqlTrackingWorkflowInstance> instances = query.GetWorkflows( options );
    Console.WriteLine( "Talált workflow: {0} db", instances.Count );

Innentől kezdve nincs más hátra, végig kell menni a példányokon. Minden SqlTrackingWorkflowInstance tartalmaz egy ActivityEvents gyűjteményt az activity szintű eseményeknek. Ha a profilban így kértük, most is ezt kell használni. Az ActivityTrackingRecordok Body tulajdonságában találhatjuk meg a kért napló sorokat:

    foreach( SqlTrackingWorkflowInstance instance in instances )
    {
        Console.WriteLine( "nnID: {0}", instance.WorkflowInstanceId );

        foreach( ActivityTrackingRecord activityRecord in instance.ActivityEvents )
        {
            Console.WriteLine( "t{0,-10:T}{1,-20}{2}", activityRecord.EventDateTime, 
activityRecord.QualifiedName, activityRecord.ExecutionStatus ); foreach( TrackingDataItem dataItem in activityRecord.Body ) { Console.WriteLine( "ttData: {0}t{1}", dataItem.FieldName, dataItem.Data ); } } }

Természetesen még véletlenül sincs benne egyik változó nevében sem, hogy extract. Ami a profilban extract, azt itt TrackingDataItemnek hívják. Ennyi, tessék kísérletezni!

A fenti példát tartalmazó teljes forráskód letölthető a devPORTALról.

 

Technorati tags: , ,

LINQ to SQL: Beteljesül az álom?

Többen kérdezték meg tőlem, hogy a LINQ to SQL valóban megoldja-e a tipikus adatkezelési problémákat, érdemes-e használni, hogyan fog hatni az alkalmazásokra és azok fejlesztésére? A kérdésre a pontos válasz, hogy a jóég tudja, de azért néhány szempontot érdemes megnézni:

 

1. Unified Storage

A Microsoft ősidők óta próbálja megoldani az egységes tároló rendszer problémáját. Tudjuk, hogy nagyon sokféle adatot akarunk kezelni, ráadásul nagyon eltérőek a tipikus adatkezelési műveletek is az egyes esetekben. Minden ilyen esetre született több-kevésbé optimalizált adattár és elérési API:

  • fájlrendszer
  • registry
  • relációs adatok
  • címtár
  • dokumentumok stb.

Nyilvánvalóan felmerül az igény az egységes tároló rendszer, a unified storage megvalósítására. Ezt az álmot már nagyon sok projekt kergette és még sokáig nem fog megvalósulni. Csak a publikussá vált projektek és kódnevek listája:

  • "Cairo": az objektum orientált operációs rendszer, kb. 1994. Lényegében semmi sem lett belőle.
  • "Hailstorm" avagy .NET My Services: a személyes adatok központosított tárháza a SOAP és a WS-* jegyében 2001-ből. Ezt ugyan kifütyülték a privacyra érzékeny kritikusok és versenytársak, de lássuk be, a Windows Live Services lényegében ennek utózengése.
  • "WinFS" avagy Windows Future Storage: előbb a relációs fájlrendszer, majd a mindent tudó, operációs rendszerbe épített relációs adatbázis álma 2003-ból, megcélozva a közvetkező Windows verziót, az akkor még Windows Longhornnak nevezett, ma Windows Vistaként ismert….izét. A WinFS blog utolsó bejegyzése épp egy éves és akárhogy is cifrázza, lényegében arról szól, hogy a WinFS-ből sem lesz semmi. Matt Warren elég tömören fogalmazza meg a projekt hangulatát:

"We on the outside used to refer to WinFS as the black hole, forever growing, sucking up all available resources, letting nothing escape and in the end producing nothing except possibly a gateway to an alternate reality. Many of our friends and co-workers had already been sucked in, and the weekly reports and horror stories were not for the weak-of-heart. […] There were not too many in the developer division that believed in the mission of WinFS."

  • "ObjectSpaces": ez inkább ORM technológiának készült előbb a .NET 1.1-hoz, majd később a 2.0-hoz. Ennek sorsáról Luca Bolognese blogbejegyzését érdemes elolvasni, beszippantotta a WinFS, ami zsákuktcának bizonyult.

Ezek tehát mind álmok, vagy ahogy a Microsoftnál szeretik mondani: víziók (lásd TechEd megnyitó előadásának bevezetőt itt smile_teeth).

Illik-e ebbe a sorba a LINQ to SQL? Szerintem nem, sőt a LINQ is kilóg belőle. Most éppen nem cél, hogy egyetlen tároló rendszerünk legyen, inkább az a cél, hogy LINQ providerek segítségével az egyes adatbázis motorokat egységesen tudjuk programozni. Ezen a területen úgy látszik jó irányba haladunk.

 

2. ORM

Nyilvánvalóan objektumokkal "szeretünk" dolgozni, sokkal barátságosabbak, mint a rekordok, mezők, attribútumok, kulcsok, relációk. Az ObjectSpaces is ORM technológiának indult, helyét valóban átveszi a LINQ to SQL. Igen, erre remekül alkalmas, valóban minimális kódolással tudunk relációs adatokat objektumokká alakítani és fordítva. Akinek azonban eddig már szüksége volt ORM-re, az vagy írt magának, vagy használt egy létező technológiát, például NHibernate-et és nem valószínű, hogy hajlandóak lesznek váltani egy új technológia kedvéért.

 

3. Produktivitás

Gyorsabban tudunk dolgozni LINQ-kel, mint a korábbi technológiákkal? Nem vagyok benne biztos. A lambda kifejezések világa először nagyon szokatlannak tűnik, eltart egy darabig, amíg megszokjuk, ráadásul nincs dizájnerünk, csak IntelliSense. Miután belerázódtunk, valóban kevesebb kódot kell írnunk, már ha eddig írtunk egyáltalán adatelérési kódot. Sokan már eddig is generálták a DAL kódot, vagy használták a VS beépített varázslóit. Mivel ezek a trükkök közvetlenül ADO.NET kódot eredményeztek a LINQ-féle indirekció nélkül, ezért már csak teljesítmény okokból sem érdemes nekik váltani. Sokaknak vannak már kész osztályaik az ADO.NET kód egyszerűsítésére, nekik valószínűleg hatékonyabb a már megismert eszközeiket használni, mint megtanulni a LINQ-et.

 

4. Architektúra

Ez szerintem a kulcskérdés: hogyan fog változni az alkalmazások felépítése a LINQ megjelenésével?

  • Az egyszerű alkalmazásoké sehogy, továbbra is szétszórva lesz benne az adatelérési kód DAL nélkül, csak éppen nem ADO.NET, hanem LINQ szintaktikával – feltéve, hogy azzal produktívabbak vagyunk.
  • A többrétegű alkalmazásoké sem fog változni, hiszen nem változhat, épp ez a lényeg. Adott egy szigorú felépítés, azt kell követni, a technológia mindegy. Itt tehát marad a DAL, a produktivitás persze dönthet arról, hogy milyen technológiával készül el (lásd az előző bekezdést).
  • Strukturálatlan alkalmazások: már most is van néhány olyan alkalmazás, amelynek igazán nincs felépítése, a VS varázslói közvetlenül odakötözték az adatbázis táblákat a felhasználói felület vezérlőkhöz. Mivel a varázslók remekül beváltak ezekben az esetekben, itt nincs helye a LINQ-nek.

Ha egy már létező alkalmazásban szükség van ORM-re, akkor ott arra már valószínűleg született egyfajta megoldás, amit nagy valószínűséggel nem fognak átírni. A LINQ to SQL tehát akkor fog ORM célokra elterjedni, ha zöld mezős alkalmazásokban van lehetőség használni és meg is éri használni (megint csak produktivitás).

 

Összegezve: a LINQ to SQL nem egy tökéletes megoldás a lassan évtizedek óta létező problémákra, hanem inkább csak egy megoldási alternatíva. Eggyel több lehetőséget kell figyelembe vennünk, amikor implementációs technológiát választunk. Mivel a Microsoft elég sokat tett fel a .NET 3.5 platformra, mindenképpen érdemes jobban megismerkedni vele.

 

Technorati tags: , , ,

Déja vu és SSCE

Letöltöttem az új Windows Mobile Device Center 6.1-et, hogy a Windows Mobile-os telefonomat tudjam szinkronizálni az Outlokkal és sajnos az élmény tisztára az ActiveSynces időkre emlékeztet: elég sűrűn szól, hogy gáz van babám, húzd ki és dugd be újra. Ami még ennél is rosszabb, hogy frissítés után nem látta az összes Outlook mappámat, így az RSS feedeket nem tudtam a telefonomra szinkronizálni. Újraindítás nem használt, mit tehet az ember, partnership törlése és újra felvétele, valamint sok fenti hibaüzenet leokézása után most látszólag működik.

Úgy gondolnám ez egy tipikus felhasználói szkenárió, aminek illene működnie és talán fontosabb, mint hogy saját képet tudjak megjeleníteni a telefonomról, mert azt bezzeg lehet.

Épp ezt a hackelést néztem, amikor a C:Users<én>AppDataRoamingMicrosoftActiveSyncProfiles<profileID> mappában megláttam egy user.sdf nevű fájlt. Aki használta már az SQL Server 2005 Compact Editiont, vagy olvasta a múltkori szösszenetemet, annak talán velem együtt az SDF-ről a Single Data File ugrik be. Nosza le is másoltam és a Visual Studio 2005 Server Explorerében létrehoztam egy új kapcsolatot, hogy megnézzem a tartalmát és valóban: 10 tábla van benne. Tele vannak GUID-okkal és bináris mezőkkel, amire nálam a VS 2005 kiakadt smile_sad Lehet, hogy más SQL verziót használnak?

Megnéztem a C:WindowsWindowsMobile mappát, de ott nem láttam SSCE-re utaló DLL-eket, arra pedig már nem volt kedvem, hogy Process Explorerrel utánajárjak a dolognak.

Azért azt jó látni, hogy a Microsoft is használja a saját dolgait, a minőség viszont még fejlődhetne…

 

Technorati tags: ,