Monthly Archives: March 2009

SQL Server programozása PL/SQL-ben

[2009.04.01.] Miután mindenki számára nyilvánvalóvá vált, hogy az Oracle Server egyáltalán nem “unbreakable”, egyre több cég keresett meg minket azzal a feladattal, hogy az alkalmazás mögött futó Oracle Servert cseréljük le Microsoft SQL Serverre, természetesen a forráskód módosítása nélkül. A két rendszer és a két nyelv között azonban számos különbség van, amit csak azzal tudtunk kiküszöbölni, hogy SQL Servernek közvetlenül megtanítottuk a PL/SQL-t.

Az Oracle által támogatott PL/SQL nyelvben számos olyan nyelvi elem található, amely már létezik az SQL Serverben, csak éppen más a szintaktikája. Ilyen például a DECODE() függvény, ami helyett T-SQL-ben CASE van, szekvenciák helyett pedig IDENTITY. Ezen kívül van sok olyan eset, ahol az adott funkció egyáltalán nem létezik T-SQL-ben, például SQL Serveren nincsenek egymásba ágyazott táblák és hiányzik az Oracle DUAL dummy táblájának megfelelője is. Nincs FOR ciklus és a triggerek is csak utasítás szintűek, míg Oracle Serveren akár sor szintűek is lehetnek. Vannak továbbá jogosultsági problémák, hiszen az SQL Server nem támogatja a sor szintű jogosultság szabályozást, az Oracle szerver viszont igen.

A probléma megoldására az MSDN Kompetencia Központon belül működő Adatbázisok és Tudásfeltárás Csoport Dr. Iváncsy Renáta vezetésével 2008. júniusában kutatási projektet indított, amelyre nagyon hamar felfigyeltek az ipari partnereink. Ennek köszönhetően a kialakult megoldást éles körülmények között fejleszthettük ki és mára már számos cégnél és intézménynél alkalmazzák.

A megoldás technikai lehetőségét az adta, hogy a Microsoft SQL Server lekérdezés feldolgozója bővíthető egy IQueryExtension interfész implementálásával. Ezt úgy kell elképzelni, mint a LINQ-es bővítő metódusokat: ha valahol olyan nyelvi elemet talál a parser, amit nem ismer, megnézi, hogy a bővítmények között van-e olyan komponens, amely megbírkózik vele. Egyszerűnek hangzik? A gyakorlatban nem az, ugyanis vannak olyan utasítások, például a SELECT, amely máshogy paraméterezhető a két nyelvben, így nem volt más választásunk, mint az SQL Server egész lekérdezés feldolgozóját kicserélni egy saját implementációra.

  Architektúra

Számos debuggolási kör és éles üzemben szerzett tapasztalat (egyeseknek a február 7-i Ügyfélkapu eset jut ilyenkor eszébe) után büszkén jelenthetjük ki, hogy nem csak, hogy implementáltuk a PL/SQL nyelvet a Microsoft SQL Serverben, de az alábbi grafikonról egyérteműen leolvasható, hogy az így nyert rendszer lekérdezés futtatási teljesítménye veri az alap implementáció teljesítményét.

Teljesítmény

Szintén a projekt létjogosultságát igazolja, hogy sok olyan fejlesztővel találkozunk a munkánk során, akik már régóta SQL Serveren szeretnének fejleszteni – hiszen bizonyítottan jobb, mint az Oracle – viszont nincs lehetősége más nyelvet megtanulni, így kvázi röghöz kötötte az Oracle a PL/SQL nyelv által.

A Microsoft MVP és Regional Director csatornákon keresztül sikerült felhívni a redmondi fejlesztőcsapat figyelmét az eredményeinkre, akik nagyon pozitívan álltak hozzá a munkánkhoz. Január vége óta a csapatunk magja Redmondban az SQL teammel szorosan együttműködve azon fáradozik, hogy az SQL Server 2008 következő javítócsomagja már tartalmazza ezt a funkciót, így a Microsoft adatbáziskezelője lesz az első olyan rendszer, amely egyszerre támogatja a T-SQL és a PL/SQL nyelvet is.

A fenti grafikonon látható teljesítmény és funkció különbségre felfigyelt a LINQ csapat is, ezért várhatóan a .NET Framework 4.0-ban a LINQ to SQL natívan PL/SQL kódot fog generálni. (Ezzel egyébként megoldottuk a LINQ csapat egyik régi problémáját, a PL/SQL-ben lévő %TYPE ugyanis lehetővé teszi a .NET-es anonymous típusok leképezését adatbázis kódra.) Mivel ez kiemelt fontosságú, ezért elképzelhető, hogy a .NET Framework 4.0 kicsit csúszni fog, cserébe lényegesen nagyobb funkcionalitást fogunk kapni. Az még nem dőlt el, hogy a LINQre épülő egyéb komponensek, például az ADO.NET Data Services már a 4.0 vagy csak egy későbbi Framework verzióban állnak át az új implementációra és használják ki annak lehetőségeit, az viszont már biztos, hogy SQL Server Data Services támogatni fogja a PL/SQL nyelvet is.

Akiket érdekel mindez a gyakorlatban, azok számára letölthető egy minta alkalmazás, amely tetszőleges PL/SQL kódot képes SQL Serveren futtatni. Akit pedig az implementációs részletek hoznak lázba, az alábbi linkről a teljes forráskódot és a kutatás teljes dokumentációját is letöltheti:

Letöltés »

Az IIS 7 beállításainak mentése és visszatöltése

Az IIS 7 egyik legfontosabb architekturális újdonsága, hogy a webkiszolgáló beállításai XML formátumú .config kiterjesztésű állományokban tárolódnak a C:WindowsSystem32inetsrvconfig mappában. Ezeknek a mentését legegyszerűbb módon parancssorból végezhetjük el, felhasználva az appcmd segédprogramot, melynek eredménye a C:WindowsSystem32inetsrvbackup mappába kerül.

A mentés elkészítésére az appcmd add backup <backupnév> parancs, a visszatöltéshez pedig az appcmd restore backup <backupnév> parancs használható.

Az IIS 6-hoz hasonlóan az IIS 7 is készít automatikus mentést a beállításokat tartalmazó állományokról, ha azok változnak. Ez az ún. Config History szolgáltatás, melyért az Application Host Helper Service felelős. Ez a szolgáltatás alapértelmezés szerint kettő percenként ellenőrzi, hogy változott-e az applicationHost.config vagy az administration.config állomány és ha igen, akkor másolatot készít róluk a C:inetpubhistory mappába. A szolgáltatás konfigurálása az applicationHost.config fájlban a configHistory szekció módosításával lehetséges.

Demó

A demóban bemutatjuk a mentés és a visszatöltés lépéseit parancssorból és egy szabadon letölthető kiegészítés használatával, majd rátérünk a Config History szolgáltatás használatára és az alapbeállítások módosítására.

A videó a képre kattintva megtekinthető böngészőben vagy a kép alatti linkre kattintva letölthető:

Mentes_Thumb

Letöltés: Mentes.wmv (18:24, 92.1 MB)

Első lépések

Első lépésként nézzük meg, hogy milyen mentések készültek korábban a rendszerről. Erre használhatjuk az appcmd list backups parancsot.

Jó tudni

Mind a Config History, mind pedig az appcmd csak a kiszolgáló szintű beállításokat menti. Az alkalmazás szintű beállítások az alkalmazások mappáiban található web.config fájlokba kerülnek, ezek mentéséről egyéb módon kell gondoskodni.

További információk

Az IE 6-nak mennie kell

Biztos sokakhoz már eljutott a hír, megjelent az Internet Explorer 8, ingyenesen letölthető, telepíthető, telepítendő! Én a béta 1 változattól kezdve használom és bevallom semmi problémám nem volt vele. Ha egy webhely nem támogatta, a Compatibility View segítségével akkor is tökéletesen lehetett használni az oldalt. Merem ajánlani. A korábbi verzióknak, különösen az IE 6-nak immár mennie kell!

Az IE 6-tal sok gond van, nem véletlenül szeretne tőle minden webfejlesztő megszabadulni. Az elmúlt hónapokban kampány indult az IE 6 kipusztítására:

Mivel nem csak webfejlesztőként, hanem felhasználóként a személyi adatokat és a biztonságot szem előtt tartva sem szerencsés az IE 6 használata, ezért mától mi is felhívjük erre az ilyen böngészővel honlapunkra látogatók figyelmét:

IE 6 figyelmeztető üzenet az MSDN Kompetencia Központ oldalán

Persze felmerül a kérdés, hogy ez hány látogatót fog érinteni? Bár az IE 6 2001. augusztus 27-én, több mint 7 éve jelent meg, még mindig meglepően sokan használják. Íme néhány általunk mért webhely statisztikája, az IE 6 arány ijesztően nagy egy ennyire elavult, ráadásul ingyenesen frissíthető termékhez képest:

IE_archive_devportal  IE6_aut
IE6_bet IE6_mezga
IE6_msdnaa IE6_msdnkk

 

Tisztában vagyok vele, hogy néhányan kényszerből (vagy mert ez a policy vagy mert valamilyen alkalmazás csak ezzel megy), de meggyőződésem, hogy nagyon sokaknál csak az akaráson múlik, hogy verziót váltanak-e.

Kedves IE 6!

Jó volt veled, de most már menj.

Üdvözlettel,

Az MSDN Kompetencia Központ csapata

Technorati Tags: ,,

Az IIS 7 konfigurációs fájljai

Az Internet Information Services 6-hoz képest az IIS 7 konfigurációs rendszere teljesen megváltozott, a metabase-t a .NET platformon már megszokott XML formátumú konfigurációs fájlok váltották fel. Az IIS 7 szorosan összefonódik a .NET platformmal, a webszerver beállításai a .NET-es alkalmazások beállításaival azonos helyen tárolódnak.

04-KonfiguracioA különböző konfigurációs fájlok hierarchiába rendeződnek, melynek csúcsán a machine.config fájl áll, amely a gépen található összes .NET-es alkalmazásra vonatkozóan tartalmaz beállításokat. A machine.config után az ún. gyökér (root) web.config fájl található, amely a gépen futó összes ASP.NET alkalmazás közös beállításait tartalmazza. A hierarchiában ezek után az IIS 7 központi konfigurációs állománya, az applicationHost.config következik, amit az egyes webhelyek, alkalmazások és mappák helyi web.config állományai követnek. Ebben a hierarchiában a beállítások öröklődnek, azaz a hierarchia felsőbb pontját megadott érték alapértelmezés szerint vonatkozik az alsóbb szintekre is. Az alsóbb szinteken van lehetőség az öröklött beállítások felüldefiniálására, illetve felsőbb szinten meg lehet tiltani a beállítások felülírását.

A fentieken kívül az IIS 7-hez még két konfigurációs fájl tartozik, amelyek azonban nem vesznek részt a hierarchiában. A redirection.config fájlt a rendszer akkor használja, ha bekonfiguráltuk az ún. Shared Configuration szolgáltatást; ebben az esetben ez a fájl határozza meg, hogy milyen megosztott mappában találhatóak a konfigurációs állományok. A másik önálló fájl az administration.config, amely kizárólag az IIS Manager által használt és a grafikus üzemeltetői felület által használt modulok beállításait tartalmazza.

Demó

A demóban bemutatjuk az IIS 7 konfigurációs fájljainak felépítését, és a Feature delegation valamint a Shared configuration szolgáltatásokat.

A videó a képre kattintva megtekinthető böngészőben vagy a kép alatti linkre kattintva letölthető:

 Konfiguracio_Thumb

Letöltés: Konfiguracio.wmv (14:55, 58.6 MB)

Első lépések

Bár a legfontosabb beállítások módosítása elvégezhető az IIS Manager felhasználói felületéről, létezhetnek olyan modulok, amelyekhez nem tartozik felhasználói felület. Ezért érdemes megismerkedni a konfigurációs fájlok belső felépítésével, illetve megtekinteni azokat a C:WindowsSystem32inetsrvconfig mappában. Mivel az IIS 7 a .NET-es konfigurációs fájlok struktúráját és logikáját követi, ezért célszerű megismerkedni a .NET-es .config fájlok használatával is.

Jó tudni

Az IIS Managerben van lehetőség az egyes szekciók felülírhatóságát szabályozni a Feature delegation modul segítségével. Ez a funkció azonban csak egész konfigurációs szekciókra használható. Ha ennél finomabban, például XML elem vagy attribútum szinten szeretnénk meghatározni, hogy az alsóbb szinteken felül lehet-e definiálni az értéket, használjuk a .NET platform szolgáltatásait: erre találták ki a lockAttributes, lockAllAttributesExcept, lockElements, lockAllElementsExcept és lockItem attribútumokat. Ezek alkalmazásához azonban közvetlenül kell módosítanunk a .config állományokat.

További információk

Kliens oldali validálás és OnClientClick

Ha egy weboldalon valaminek a törlésére készítünk funkciót, postback előtt mindig célszerű rákérdeznünk a felhasználónál, hogy valóban szeretné-e törölni a kiválasztott elemet. Az ilyen “valóban használni kívánja a légzsákot” jellegű kérdések megvalósítására kiváló hely a Button osztály OnClientClick tulajdonsága, az egyetlen hátránya, hogy összevész a validator vezérlők kliens oldali szkriptjeivel.

A megerősítést kérő ablak feldobása mindössze ennyi:

    <asp:Button ID="btnGo" runat="server" Text="Mehet" 
        OnClientClick="return confirm('Biztos, hogy ezt akarod?');" 
        onclick="btnGo_Click" />

Ez tökéletesen működik egészen addig, amíg a gombhoz nem kapcsolódik validator, ebben az esetben ugyanis hiába van engedélyezve a validator kliens oldali szkriptje, megtörténik a postback és csak a válasz megérkezése után jelenik meg a hibaüzenet kliens oldalon. E helyzet még rosszabb, ha a gomb szerver oldali eseménykezelőjéből kifelejtjük a Page.IsValid ellenőrzést, mert akkor még le is fut a teljes kódunk, mintha a validator ott sem lenne. A probléma tehát az, hogy rossz a kliens oldali szkriptek futásának sorrendje.

Szerencsére a validatorokhoz van kliens oldali API, ami részben dokumentált, részben pedig erős nézés módszerével (ld. pl. IE8 script debugger) megfejthető. Ez utóbbi úton jutottam az alábbi megoldáshoz, ami megoldja a fenti problémát:

  <asp:Button ID="btnGo" runat="server" Text="Mehet" 
    OnClientClick="Page_ClientValidate('myGroup'); if(!Page_IsValid) return false; return confirm('Biztos, hogy ezt akarod?');" 
    onclick="btnGo_Click" 
ValidationGroup="myGroup" />

Fiddlerezzünk JSONt localhoston

Egy klienshez ADO.NET Data Services-zel készítettem a szerver oldali komponenst, ami JSON-ban küldte vissza az adatokat a kliensnek. Hibakeresés közben bele kellett néznem az utazó adatokba, ami még Fiddlerrel sem bizonyult egyszerűnek.

Fiddler kontra ASP.NET Development Server

A Fiddler egyik óriási előnye a kényelmes használata, nem kell konfigurálni semmit (na jó, Firefoxot kell), csak elindítani és máris mutatja a böngésző és a szerver közötti forgalmat. Kivéve, ha localhoston dolgozunk, azt ugyanis némi trükközés nélkül nem képes elkapni. Megoldás lehet localhost helyett a gépnév használata, ami tökéletesen működik IIS-sel, az ASP.NET Development Server viszont csak localhostra hallgat, arra is csak IPv4-en.

A trükk az, hogy FQDN-ként az ipv4.fiddler hostot kell használni és máris megy minden, mint a karikacsapás.

Böngésző kontra Astoria

Az ADO.NET Data Services (Astoria) által szolgáltatott URL-ek alapértelmezés szerint Atom formátumban küldik vissza az adatokat, amire korunk brilliáns böngészői azonnal ráharapnak és megpróbálják az RSS olvasó oldalukkal megjeleníteni. Ami gyakorlatilag használhatatlanná teszi a böngészőt, mint Astoria klienst:

A Northwind Categories táblája Firefoxban

Természetesen kattintgathatnám a jobb egérgombot és a View Source menüpontot az Atom feed forrásának megtekintéséhez, de ezt percenként többször nem akaródzik megtenni.

Nem beszélve arról, ha a kliensnek nem Atom, hanem JSON formátumú adat kell. Ehhez szerver oldalon nem kell konfigurálni semmit, mindössze annyi szükséges, hogy a kliens JSONt kérjen, és ezt a HTTP request Accept fejlécében feltüntesse. A böngésző végképp nem alkalmas arra, hogy request header mezőket faragjunk vele…

Fiddler és az Accept fejléc

A Fiddlerben van egy kiváló Request Builder funkció, amivel összerakhatjuk a kérést és még a fejléc mezőket is megadhatjuk. Feltüntetve, hogy Accept: application/json, máris JSONban jön a válasz:

Fiddler Request Builder JSON-hoz

Hibalehetőségek:

  • HTTP Error 404: Elírtuk az URL-t, például Customers helyett Costumers lett.
  • HTTP Error 415: Elírtuk az Accept fejlécet, például application helyett applicaiton sikerült.

Fiddler és a JSON

Már csak annyi maradt hátra, hogy a JSON választ meg kellene nézni. Ha hostként ipv4.fiddlert adtunk meg, akkor a bal oldali listából ki tudjuk választani a kérésünket és jobb oldalon az Inspectors fülön látjuk is a forgalmat:

Fiddler: Raw inspector

Így elég nehézkes JSONt nézegetni, ezért érdemes letölteni a CodePlexről az ingyenes JsonViewert. A letölthető csomagban találunk egy önálló .exe alkalmazást, egy Fiddler plugint és egy Visual Studioba beépülő visualizert. A telepítés az útmutató követve pikkpakk megvan és a Fiddler újraindítása után máris barátságosabb formában láthatjuk a JSON választ:

JsonViewer Fiddlerben

Lockdown Policy Prevents This Request

Az egyik webalkalmazásunkkal kapcsolatban több megkeresés érkezett, hogy a felhasználókat nagyon zavarja a sok tanúsítvány figyelmeztetés, ezért jó lenne a Root CA tanúsítványát közvetlenül letölthetővé tenni a bejelentkező oldalról. Fogtam hát a tanúsítványkiadó tanúsítványát .cer formátumban, felmásoltam a webszerverre, majd kissé meglepődve bámultam a böngészőben megjelenő 404 – Not Found hibaüzenetet.

Persze IIS 6-ról lévén szó, tudtam, hogy akármit nem enged letölteni a webszerver, ezért végignéztem a Mime Map beállításokat, de nem segített. Kénytelen voltam megnézni a webszerver naplóját (olvasott embernek párja nincs 🙂 ), ahol nem csak a HTTP hibakód, hanem az alhibakód is látszik: 404.2. Erről a Technet oldalon kiderült, hogy a jelentése Lockdown Policy Prevents This Request, tehát valami ISAPI vagy CGI a ludas.

Az Application Configuration ablakot megnyitva megjelent a hiba oka:

cer extension mapping

A .cer kiterjesztés kiszolgálásáért az ASP (nem ASP.NET!) feldolgozó motor felelős, ami persze alapértelmezés szerint nincs engedélyezve az IIS 6 Web Server Extensions listájában. Két megoldás maradt:

  1. Az ASP motor engedélyezése. Talán nem meglepő, hogy nem ezt választottam.
  2. Ha úgysincs engedélyezve az ASP, akkor valószínűleg szükségünk sincs rá, tehát nem kell, hogy a .cer fájlokra érkező kéréseket ő szolgálja ki, ezért nyugodt lelkiismerettel rákattintottam a Remove gombra a fenti listában.

IdentityNotMappedException

Nem először sikerül belefutnom az alábbi kivételbe, szinte mindig valamilyen egyedi telepítő futtatása közben:

“System.Security.Principal.IdentityNotMappedException: Nem lehet lefordítani néhány azonosítási hivatkozást, illetve egyet sem.”

Na kösz, és ez mit jelent?

Angolul egy kicsit közelebb juthatunk a megoldáshoz:

“Some or all identity references could not be translated.”

Már csak az a kérdés, hogy mi az az identity reference és mi az a translate. A problémát az eddigi esetekben mindig az jelentette, hogy a telepítő jogosultságot akart osztogatni egy mappán vagy registry kulcson, mégpedig egy konkrét felhasználó számára, tehát itt kell elkezdenünk keresgélni. A feladat valóban megoldható .NET-ben, a System.Security.Principal névteret használva, az NTAccount osztály segítségével meg tudok nevezni (reference) egy felhasználót (identity) és tudok neki jogot adni. A Windows hozzáférés szabályozási listáiban (Access Control List – ACL) az Access Control Entry-k mindig SID (Security IDentifier)-jogosultság párosokat tartalmaznak, tehát hiába adok meg egy felhasználó nevet, azt mindig SID-dé kell változtatni (translate), hogy tudjunk neki jogot adni. Szerencsére ezt a háttérben a .NET Framework osztályai megoldják helyettünk.

A fenti IdentityNotMappedException akkor keletkezik, amikor nem sikerült a névből SIDet gyártani, ez pedig tipikusan akkor fordul elő, amikor a “Rendszergazda” vagy a “Hálózatszolgáltatás” felhasználóra vagy éppen a “Rendszergazdák” csoportra hivatkozunk és a kódunkat angol operációs rendszeren futtatjuk, ahol nincs ilyen csoport. Vagy éppen fordítva, magyar Windowson keres a kódunk “Network Service” nevű felhasználót.

Ha a kódot nem mi írtuk, akkor a megoldás egy csoport létrehozása “Network Service” néven, amibe belepakoljuk a “Hálózatszolgáltatás” felhasználót és egy csapásra működni fog a kód.

Ha a kódot mi írtuk, akkor a megoldás az, hogy elszégyelljük magunkat, mert még nem hallottunk az ún. nevezett well-known SID-ekről vagy mert lusták voltunk használni őket. A standard felhasználóknak és csoportoknak a SID-jük is standard, nem csoda, hogy van rá enum a .NET Frameworkben, úgy hívják hogy WellKnownSidType. A használata pofonegyszerű, annyi a lényeg, hogy nem az NTAccount osztályt kell használni, hanem annak testvérét, a SecurityIdentifiert:

    DirectoryInfo di = new DirectoryInfo( @"C:Teszt" );
    DirectorySecurity acl = di.GetAccessControl();

    SecurityIdentifier sid = new SecurityIdentifier( WellKnownSidType.NetworkServiceSid, null );
    FileSystemAccessRule ace = new FileSystemAccessRule( sid, FileSystemRights.Write, AccessControlType.Deny );
    acl.AddAccessRule( ace );

    di.SetAccessControl( acl );

Ez már nem fog olyan könnyen elhasalni.

Elindul a Kitörés program

Kérdés: Készítettem egy ASP.NET alkalmazást, ki fogja nekem ingyenesen hosztolni?

Egy lehetséges válasz:

“A program keretében 2009 tavaszán a Microsoft és a Sense/Net közös programba kezd. Ennek keretében a Microsoft webes technológiáit és alkalmazásait (ASP.NET, Silverlight, Windows Server 2008, SQL Server 2008, IIS7,Visual Studio 2008) használatát segítjük elő, felhasználva a hazai gyártású Sense/Net 6.0 nyílt forrású tartalomkezelo és portál szoftvert, amely a fenti technológiákra épül.

A program eddig előregisztrációs fázisban volt. Az egyeztetések és technikai feltételek megteremtésének lezárultával várhatóan március 15-én megindul, úgyhogy mostantól beindult a végleges regisztráció!”

Bővebbe információk: http://devportal.hu/kitores

Ti hova szoktátok feltölteni?

Felhasználó utánzatok

ASP.NET-es fejlesztés közben gyakran előfordul, hogy egy olyan funkciót kell megvalósítanunk, amely felhasználói fiókhoz vagy szerepkörhöz kötött, de még nincs kész a projektünkben a regisztráció vagy a bejelentkezés oldal.Ilyenkor az egyik lehetőség a felhasználói adatbázis gyors összekattintgatása, de ha ezt nem tehetjük meg, akkor nincs más megoldás, mint saját Membership- és Role providerek készítése, amelyek ugyanúgy bejelentkeztetik a felhasználót, de nem igényelnek adatbázist. Ez egyszerűbb, mint azt első hallásra gondolnánk.

Ha már megvan az ASP.NET alkalmazásunk, az App_Code mappában hozzunk létre egy új osztályt, amely a dummy felhasználóinkat, azaz felhasználó utánzatainkat fogja kezelni. Ezt a DummyMembershipProvider osztályt a MembershipProvider ősosztályból kell származtatnunk. Mivel ez abstract ősosztály, a Studio rögtön fel fogja kínálni az összes felülírandó metódust, melyből a bejelentkezés működéséhez legalább a ValidateUsert implementálnunk kell, például így:

    public class DummyMembershipProvider : MembershipProvider
    {
        private Dictionary<string, string> _users = null;

        internal static string AdminUserName = "admin".ToLowerInvariant();
        internal static string MemberUserName = "user".ToLowerInvariant();

        public override void Initialize( string name, 
                                         NameValueCollection config )
        {
            this._users = new Dictionary<string, string>();
            this._users.Add( AdminUserName, AdminUserName );
            this._users.Add( MemberUserName, MemberUserName );

            base.Initialize( name, config );
        }

        public override bool ValidateUser( string username, string password )
        {
            if( this._users.ContainsKey( username.ToLowerInvariant() ) )
            {
                return password.Equals( this._users[ username ], 
                                        StringComparison.OrdinalIgnoreCase );
            }
            return false;
        }

        // Itt még sok metódus van, amely NotImplementedExceptiont dob...
    }

A fenti példa tartalmaz egy admin és egy user felhasználót, a jelszava mindkettőnek megegyezik a felhasználónevével.

Ahhoz, hogy mindez működjön, még át kell kapcsolnunk az ASP.NET-et erre a providerre a web.configban:

    <authentication mode="Forms"/>
    <membership defaultProvider="DummyMembershipProvider">
        <providers>
            <add name="DummyMembershipProvider" type="DummyMembershipProvider"/>
        </providers>
    </membership>

Ezzel már be is tudunk jelentkezni a két felhasználónkkal. Ha még szerepkörök is kellenek, akkor egy DummyRoleProvidert kell származtatnunk az abstract RoleProvider ősosztályból, amelyből legalább az IsUserInRole metódusra szükségünk lesz:

    public class DummyRoleProvider : RoleProvider
    {
        internal static string AdminRoleName = "admins";
        internal static string MemberRoleName = "members";

        public override bool IsUserInRole( string username, string roleName )
        {
            string[] roles = this.GetRolesForUser( username );
            return roles.Contains( roleName );
        }

        public override string[] GetRolesForUser( string username )
        {
            if( username.Equals( DummyMembershipProvider.AdminUserName,                                  StringComparison.OrdinalIgnoreCase ) )
            {
                return new string[] { DummyRoleProvider.AdminRoleName };
            }
            else if( username.Equals( DummyMembershipProvider.MemberUserName,                                       StringComparison.OrdinalIgnoreCase ) )
            {
                return new string[] { DummyRoleProvider.MemberRoleName };
            }
            else
            {
                return new string[ 0 ];
            }
        }

        // ...
    }

Persze ez sem működik egy kis konfigurálgatás nélkül, de szerencsére csak ennyi kell a web.configba:

    <roleManager enabled="true" defaultProvider="DummyRoleProvider">
        <providers>
            <add name="DummyRoleProvider" type="DummyRoleProvider"/>
        </providers>
    </roleManager>

A fenti két osztály és a hozzá tartozó konfigurációs XML egyébként rettenetesen könnyen kopipésztelhető egyik projektből a másikba és tada, máris van jogosultság-szabályozás a projektben.

A cikkhez tartozó mellékletben a két osztály teljes forráskódja megtalálható.