Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
által Scott Mitchell
Ebben az oktatóanyagban bemutatjuk, hogyan jeleníthet meg egy barátságos, informatív hibaüzenetet, ha kivétel történik egy ASP.NET adat-webvezérlő beszúrási, frissítési vagy törlési művelete során.
Bevezetés
Egy ASP.NET webalkalmazás adatainak rétegzett alkalmazásarchitektúrával történő használata a következő három általános lépésből áll:
- Határozza meg, hogy az üzleti logikai réteg milyen metódusát kell meghívni, és milyen paraméterértékeket kell megadnia. A paraméterértékek lehetnek kemény kódolt, programozottan hozzárendelt vagy a felhasználó által megadott bemenetek.
- Hívja meg a metódust.
- Az eredmények feldolgozása. Adatok visszaadására használható BLL-metódus meghívása esetén ez magában foglalhatja az adatok adat-webvezérlőhöz való kötését. Az adatokat módosító BLL-metódusok esetében ez lehet például egy visszatérési értéken alapuló művelet végrehajtása, vagy a 2. lépésben felmerülő kivétel kecses kezelése.
Ahogy az előző oktatóanyagban láttuk, az ObjectDataSource és az adat webes vezérlők bővíthetőségi pontokat biztosítanak az 1. és a 3. lépéshez. A GridView például aktiválja az eseményt RowUpdating , mielőtt a mezőértékeket hozzárendeli az ObjectDataSource gyűjteményéhez UpdateParameters ; az esemény azután RowUpdated jön létre, hogy az ObjectDataSource befejezte a műveletet.
Már megvizsgáltuk az 1. lépés során aktiválódott eseményeket, és láttuk, hogyan használhatók a bemeneti paraméterek testreszabására vagy a művelet megszakítására. Ebben az oktatóanyagban a művelet befejezése után aktiválódott eseményekre fordítjuk a figyelmünket. Ezekkel a posztszintű eseménykezelőkkel többek között megállapíthatjuk, hogy történt-e kivétel a művelet során, és elegánsan kezeljük azt, és a szokásos ASP.NET kivételoldal helyett egy barátságos, informatív hibaüzenetet jelenítünk meg a képernyőn.
A posztszintű események használatának szemléltetéséhez hozzunk létre egy lapot, amely egy szerkeszthető GridView-ban listázza a termékeket. A termék frissítésekor, ha kivétel lép fel, a ASP.NET lap egy rövid üzenetet jelenít meg a GridView fölött, amely elmagyarázza, hogy probléma történt. Lássunk hozzá!
1. lépés: Termékek szerkeszthető GridView-jának létrehozása
Az előző oktatóanyagban létrehoztunk egy szerkeszthető GridView-t mindössze két mezővel és ProductNameUnitPrice. Ehhez további túlterhelést kellett létrehoznia az ProductsBLL osztály metódusához UpdateProduct , amely csak három bemeneti paramétert fogadott el (a termék nevét, árát és azonosítóját), szemben az egyes termékmezők paraméterével. Ebben az oktatóanyagban ismét gyakoroljuk ezt a technikát, létrehozva egy szerkeszthető GridView-t, amely megjeleníti a termék nevét, egységenkénti mennyiségét, egységárát és készleten lévő egységeit, de csak a név, az egységár és a készleten lévő egységek szerkesztését teszi lehetővé.
Ennek a forgatókönyvnek a megoldásához szükség lesz a UpdateProduct metódus újabb túlterhelésére, amely négy paramétert fogad el: a termék nevét, egységárát, készleten lévő egységeket és azonosítót. Adja hozzá a következő metódust a ProductsBLL osztályhoz:
[System.ComponentModel.DataObjectMethodAttribute(
System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, decimal? unitPrice, short? unitsInStock,
int productID)
{
Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
if (products.Count == 0)
// no matching record found, return false
return false;
Northwind.ProductsRow product = products[0];
product.ProductName = productName;
if (unitPrice == null) product.SetUnitPriceNull();
else product.UnitPrice = unitPrice.Value;
if (unitsInStock == null) product.SetUnitsInStockNull();
else product.UnitsInStock = unitsInStock.Value;
// Update the product record
int rowsAffected = Adapter.Update(product);
// Return true if precisely one row was updated, otherwise false
return rowsAffected == 1;
}
Ezzel a módszerrel készen állunk arra, hogy létrehozzuk a ASP.NET lapot, amely lehetővé teszi a négy termékmező szerkesztését. Nyissa meg a ErrorHandling.aspx lapot a EditInsertDelete mappában, és adjon hozzá egy GridView-t a laphoz a Tervezőn keresztül. Kösse a GridView-t egy új ObjectDataSource-hoz, térképezze fel a Select() metódust az ProductsBLL osztály GetProducts() metódusára, és a Update() metódust az imént létrehozott UpdateProduct túlterhelésre.
1. ábra: A négy bemeneti paramétert elfogadó túlterhelési metódus használata UpdateProduct (kattintson ide a teljes méretű kép megtekintéséhez)
Ez létrehoz egy ObjectDataSource-t egy UpdateParameters négy paramétert tartalmazó gyűjteménysel és egy GridView-val, amely minden termékmezőhöz tartalmaz egy mezőt. Az ObjectDataSource deklaratív jelölése hozzárendeli a OldValuesParameterFormatString tulajdonságnak az original_{0} értéket, ami kivételt okoz, mivel a BLL-osztályok nem várják, hogy bemeneti paraméterként a original_productID átadásra kerüljön. Ne felejtse el teljesen eltávolítani ezt a beállítást a deklaratív szintaxisból (vagy állítsa be az alapértelmezett értékre). {0}
Ezután csökkentsd le a GridView-t, hogy csak a ProductName, QuantityPerUnit, UnitPrice és UnitsInStock BoundFields szerepeljen benne. Emellett nyugodtan alkalmazhat minden szükségesnek ítélt mezőszintű formázást (például a HeaderText tulajdonságok módosítását).
Az előző oktatóanyagban megvizsgáltuk, hogyan formázzuk a UnitPrice BoundFieldet pénznemként mind csak olvasható, mind szerkesztési módban. Csináljuk ugyanezt itt is. Ne feledje, hogy a BoundField DataFormatString tulajdonságát {0:c}-re, a HtmlEncode tulajdonságát false-re, valamint a ApplyFormatInEditMode tulajdonságát true-re kell beállítani, ahogyan az a 2. ábrán látható.
2. ábra: A BoundField konfigurálása UnitPrice pénznemként való megjelenítésre (kattintson ide a teljes méretű kép megtekintéséhez)
A UnitPrice pénznemként való megjelenítéséhez a szerkesztőfelületen létre kell hoznia egy eseménykezelőt a GridView RowUpdating eseményéhez, amely a pénznem formátumú sztringet decimal értékké alakítja. Ne feledje, hogy az RowUpdating előző oktatóanyag eseménykezelője is ellenőrizte, hogy a felhasználó adott-e UnitPrice értéket. Ebben az oktatóanyagban azonban engedjük meg, hogy a felhasználó kihagyja az árat.
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
if (e.NewValues["UnitPrice"] != null)
e.NewValues["UnitPrice"] =decimal.Parse(e.NewValues["UnitPrice"].ToString(),
System.Globalization.NumberStyles.Currency);
}
A GridView tartalmaz egy QuantityPerUnit BoundFieldet, de ennek a BoundFieldnek csak megjelenítési célokra kell lennie, és a felhasználónak nem szabad szerkesztenie. Ennek elrendezéséhez egyszerűen állítsa a BoundFields ReadOnly tulajdonságát true-re.
3. ábra: A BoundField Read-Only létrehozása QuantityPerUnit (ide kattintva megtekintheti a teljes méretű képet)
Végül jelölje be a "Szerkesztés engedélyezése" jelölőnégyzetet a GridView intelligens címkéjén. A lépések elvégzése után a ErrorHandling.aspx lap tervezőjének a 4. ábrához hasonlóan kell kinéznie.
Távolítsa el az összes fölösleges BoundField elemet, és jelölje be a "Szerkesztés engedélyezése" jelölőnégyzetet.
4. ábra: Távolítsa el az összeset, csak a szükséges boundfieldeket, és jelölje be a Szerkesztés engedélyezése jelölőnégyzetet (kattintson ide a teljes méretű kép megtekintéséhez)
Jelenleg az összes termékProductNameQuantityPerUnit, , UnitPriceés UnitsInStock mező listája megtalálható, azonban csak a , ProductNameés UnitPrice a UnitsInStockmezők szerkeszthetők.
5. ábra: A felhasználók mostantól egyszerűen szerkeszthetik a termékek nevét, árát és egységét a készletmezőkben (kattintással megtekinthetik a teljes méretű képet)
2. lépés: A kivételek elegáns kezelése DAL-Level
Bár a szerkeszthető GridView csodálatosan működik, amikor a felhasználók jogi értékeket adnak meg a szerkesztett termék nevének, árának és készleten lévő egységeinek, az illegális értékek megadása kivételt eredményez. Az ProductName érték kihagyása például a NoNullAllowedException kivétel kiváltását eredményezi, mivel az ProductName osztály ProductsRow tulajdonságának AllowDBNull tulajdonsága false értékre van állítva; ha az adatbázis leáll, a TableAdapter SqlException kivételt fog dobni, amikor megpróbál csatlakozni az adatbázishoz. Anélkül, hogy bármilyen műveletet hajtanak végre, ezek a kivételek az adatelérési rétegből az üzleti logikai rétegbe, majd a ASP.NET oldalra, végül pedig a ASP.NET futtatókörnyezetbe lépnek.
Attól függően, hogy a webalkalmazás hogyan van konfigurálva, és hogy honnan látogatja-e meg az alkalmazást localhost, egy kezeletlen kivétel általános kiszolgálóhiba-oldalt, részletes hibajelentést vagy felhasználóbarát weblapot eredményezhet. Tekintse meg a Webalkalmazás-hibakezelés ASP.NET-ben és a customErrors elem részt, hogy további információkat kapjon arról, hogyan reagál az ASP.NET futtatókörnyezet egy kezeletlen kivételre.
A 6. ábra azt a képernyőt mutatja, amely akkor jelenik meg, amikor ProductName érték megadása nélkül próbál frissíteni egy terméket. Ez az alapértelmezett részletes hibajelentés jelenik meg, amikor áthalad localhost.
6. ábra: A termék nevének kihagyása kivételadatokat jelenít meg (ide kattintva megtekintheti a teljes méretű képet)
Bár az ilyen kivétel részletei hasznosak az alkalmazás tesztelése során, kevésbé ideális, ha egy végfelhasználó ilyen képernyőt lát egy kivétel esetén. A végfelhasználó valószínűleg nem tudja, mi az a NoNullAllowedException, vagy mi okozta. Jobb módszer, ha egy felhasználóbarátabb üzenetet jelenít meg a felhasználónak, amely elmagyarázza, hogy problémák jártak a termék frissítésével kapcsolatban.
Ha a művelet végrehajtása során kivétel történik, az ObjectDataSource-ban és az adat-webvezérlőben lévő posztszintű események lehetővé teszik annak észlelését és a kivétel megszakítását a ASP.NET futtatókörnyezetig. Példánkban hozzunk létre egy eseménykezelőt a GridView eseményéhez RowUpdated , amely meghatározza, hogy aktiválódott-e egy kivétel, és ha igen, a kivétel részleteit egy Címke webvezérlőben jeleníti meg.
Először adjon hozzá egy címkét az ASP.NET laphoz, állítsa be a ID tulajdonságát, és törölje a ExceptionDetails tulajdonságát. Annak érdekében, hogy felhívja a felhasználó figyelmét erre az üzenetre, állítsa a tulajdonságát CssClassWarningegy CSS-osztályra, amelyet az előző oktatóanyagban adtunk hozzá a Styles.css fájlhoz. Ne feledje, hogy ez a CSS-osztály miatt a címke szövege piros, dőlt, félkövér, extra nagy betűtípussal jelenik meg.
7. ábra: Címke webvezérlő hozzáadása a laphoz (ide kattintva megtekintheti a teljes méretű képet)
Mivel azt szeretnénk, hogy ez a Címke web vezérlőelem csak közvetlenül a kivétel bekövetkezése után legyen látható, állítsa a tulajdonságát Visible hamis értékre az Page_Load eseménykezelőben:
protected void Page_Load(object sender, EventArgs e)
{
ExceptionDetails.Visible = false;
}
Ezzel a kóddal az első oldallátogatás és az azt követő visszalépések során a ExceptionDetails vezérlő tulajdonsága Visible a következőre falselesz állítva: . Ha egy DAL- vagy BLL-szintű kivételt észlelünk a GridView eseménykezelőjében, a RowUpdated vezérlő ExceptionDetails tulajdonságát igaz értékre állítjuk. Mivel a webvezérlő eseménykezelői a lap életciklusában lévő Page_Load eseménykezelő után fordulnak elő, a címke megjelenik. Azonban a következő visszaadáskor az Page_Load eseménykezelő visszaállítja a Visible tulajdonságot false-ra, így azt ismét elrejti a nézetből.
Megjegyzés:
Alternatívaként megszüntethetjük a ExceptionDetails vezérlőelem Visible tulajdonságának beállításának szükségességét azáltal, hogy Page_Load tulajdonságát Visible értékként meghatározzuk a deklaratív szintaxisban, és letiltjuk a nézetállapotot (a false tulajdonságot EnableViewState értékre állítva). Ezt az alternatív módszert egy későbbi oktatóanyagban fogjuk használni.
A Címke vezérlőelem hozzáadásával a következő lépés az eseménykezelő létrehozása a GridView eseményéhez RowUpdated . Válassza ki a GridView-t a Tervezőben, lépjen a Tulajdonságok ablakra, és kattintson a Villám ikonra a GridView eseményeit felsorolva. Már lennie kell egy bejegyzésnek a GridView eseményéhez RowUpdating , mivel az oktatóanyag korábbi részében létrehoztunk egy eseménykezelőt ehhez az eseményhez. Hozzon létre egy eseménykezelőt is az RowUpdated eseményhez.
8. ábra: Eseménykezelő létrehozása a GridView eseményéhez RowUpdated
Megjegyzés:
Az eseménykezelőt a kód mögötti osztályfájl tetején található legördülő listákon keresztül is létrehozhatja. Válassza ki a GridView elemet a bal oldali legördülő listából, az RowUpdated eseményt pedig a jobb oldali listából.
Az eseménykezelő létrehozásakor a következő kód lesz hozzáadva a ASP.NET lap kód mögötti osztályához:
protected void GridView1_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
}
Az eseménykezelő második bemeneti paramétere egy GridViewUpdatedEventArgs típusú objektum, amely három érdekes tulajdonsággal rendelkezik a kivételek kezeléséhez:
-
Exceptiona kidobott kivételre való hivatkozás; ha nem történt kivétel, a tulajdonság értéke a következő lesz:null -
ExceptionHandledlogikai érték, amely azt jelzi, hogy a kivételt kezelték-e azRowUpdatedeseménykezelőben; hafalse(az alapértelmezett), a kivételt újradobják, továbbhaladva az ASP.NET futtatókörnyezetig. -
KeepInEditModeha a szerkesztett GridView sortruevan állítva, akkor szerkesztési módban marad; hafalsevan (alapértelmezett), a GridView sor visszaáll olvasási módba.
A kódnak ezután ellenőriznie kell, hogy Exception nem null-e, ami azt jelenti, hogy kivétel történt a művelet végrehajtása során. Ha ez a helyzet, a következőt szeretnénk:
- Felhasználóbarát üzenet megjelenítése a
ExceptionDetailscímkében - Azt jelzi, hogy a kivételt kezelték
- A GridView sor megtartása szerkesztési módban
A következő kód a következő célkitűzéseket valósítja meg:
protected void GridView1_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
if (e.Exception != null)
{
// Display a user-friendly message
ExceptionDetails.Visible = true;
ExceptionDetails.Text = "There was a problem updating the product. ";
if (e.Exception.InnerException != null)
{
Exception inner = e.Exception.InnerException;
if (inner is System.Data.Common.DbException)
ExceptionDetails.Text +=
"Our database is currently experiencing problems." +
"Please try again later.";
else if (inner is NoNullAllowedException)
ExceptionDetails.Text +=
"There are one or more required fields that are missing.";
else if (inner is ArgumentException)
{
string paramName = ((ArgumentException)inner).ParamName;
ExceptionDetails.Text +=
string.Concat("The ", paramName, " value is illegal.");
}
else if (inner is ApplicationException)
ExceptionDetails.Text += inner.Message;
}
// Indicate that the exception has been handled
e.ExceptionHandled = true;
// Keep the row in edit mode
e.KeepInEditMode = true;
}
}
Ez az eseménykezelő először azt ellenőrzi, hogy a e.Exception megegyezik-e a null-jel. Ha nem, akkor a ExceptionDetails címke tulajdonsága Visible "Hiba történt a termék frissítésekor" értékre trueText van állítva. A tényleges kivétel részletei az e.Exception objektum InnerException tulajdonságában találhatók. A rendszer megvizsgálja ezt a belső kivételt, és ha egy adott típusú, egy további, hasznos üzenetet fűz a ExceptionDetails címke tulajdonságához Text . Végül a ExceptionHandled és KeepInEditMode tulajdonságok mind a true értékre vannak állítva.
A 9. ábrán az oldal képernyőképe látható, amikor kihagyja a termék nevét; A 10. ábra egy illegális UnitPrice érték (-50) megadásakor mutatja az eredményeket.
9. ábra: A ProductName BoundFieldnek tartalmaznia kell egy értéket (kattintson ide a teljes méretű kép megtekintéséhez)
10. ábra: A negatív UnitPrice értékek nem engedélyezettek (ide kattintva megtekintheti a teljes méretű képet)
A e.ExceptionHandled tulajdonság true beállításával az RowUpdated eseménykezelő jelezte, hogy a kivételt kezelte. Ezért a kivétel nem fog propagálódni az ASP.NET futtatókörnyezetig.
Megjegyzés:
A 9. és a 10. ábra az érvénytelen felhasználói bemenet miatt felmerülő kivételek kezelésére szolgáló kecses módot mutat. Ideális esetben azonban az ilyen érvénytelen bemenetek először soha nem érik el az üzleti logikai réteget, mivel a ASP.NET oldalnak biztosítania kell, hogy a felhasználó bemenetei érvényesek legyenek az ProductsBLL osztály metódusának meghívása UpdateProduct előtt. A következő oktatóanyagban bemutatjuk, hogyan adhat hozzá érvényesítési vezérlőket a szerkesztő- és beszúrási felületekhez annak biztosítása érdekében, hogy az üzleti logikai rétegbe küldött adatok megfeleljenek az üzleti szabályoknak. Az érvényesítési vezérlők nem csak a felhasználó által megadott adatok érvényességéig megakadályozzák a UpdateProduct metódus meghívását, hanem informatívabb felhasználói élményt is biztosítanak az adatbeviteli problémák azonosításához.
3. lépés: BLL-Level kivételkezelés elegáns módon
Adatok beszúrása, frissítése vagy törlésekor az adatelérési réteg kivételt okozhat egy adattal kapcsolatos hiba miatt. Előfordulhat, hogy az adatbázis offline állapotban van, egy szükséges adatbázistábla-oszlopban nincs megadva érték, vagy a táblaszintű korlátozást megsértették. A szigorúan az adatokkal kapcsolatos kivételek mellett az üzleti logikai réteg kivételekkel jelezheti, hogy mikor szegték meg az üzleti szabályokat. Az Üzleti logikai réteg létrehozása oktatóanyagban például hozzáadtunk egy üzleti szabályellenőrzést az eredeti UpdateProduct túlterheléshez. Pontosabban, ha a felhasználó megszüntetettként jelölt meg egy terméket, azt követeltük meg, hogy ne a termék legyen az egyetlen, amelyet a szállítója biztosít. Ha ezt a feltételt megszegték, egy ApplicationException dobás történt.
UpdateProduct Az oktatóanyagban létrehozott túlterheléshez adjunk hozzá egy olyan üzleti szabályt, amely megtiltja, hogy a UnitPrice mező olyan új értékre legyen beállítva, amely meghaladja az eredeti UnitPrice érték kétszeresét. Ehhez állítsa be a UpdateProduct túlterhelést úgy, hogy végrehajtsa ezt az ellenőrzést, és a szabály megsértése esetén egy ApplicationException hibát jelez. A frissített módszer a következő:
public bool UpdateProduct(string productName, decimal? unitPrice, short? unitsInStock,
int productID)
{
Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
if (products.Count == 0)
// no matching record found, return false
return false;
Northwind.ProductsRow product = products[0];
// Make sure the price has not more than doubled
if (unitPrice != null && !product.IsUnitPriceNull())
if (unitPrice > product.UnitPrice * 2)
throw new ApplicationException(
"When updating a product price," +
" the new price cannot exceed twice the original price.");
product.ProductName = productName;
if (unitPrice == null) product.SetUnitPriceNull();
else product.UnitPrice = unitPrice.Value;
if (unitsInStock == null) product.SetUnitsInStockNull();
else product.UnitsInStock = unitsInStock.Value;
// Update the product record
int rowsAffected = Adapter.Update(product);
// Return true if precisely one row was updated, otherwise false
return rowsAffected == 1;
}
Ezzel a változással minden olyan árfrissítés, amely a meglévő ár kétszeresénél nagyobb, egy ApplicationException kivétel dobását eredményezi. A DAL-ból származó kivételhez hasonlóan ez a BLL-emelt ApplicationException is észlelhető és kezelhető a GridView eseménykezelőjében RowUpdated . Valójában az RowUpdated eseménykezelő kódja a megírt módon megfelelően észleli ezt a kivételt, és megjeleníti a ApplicationExceptiontulajdonság Message értékét. A 11. ábrán egy képernyőfelvétel látható, amikor egy felhasználó megpróbálja frissíteni a Chai árát 50,00 dollárra, ami több mint kétszerese a jelenlegi 19,95 dolláros árnak.
11. ábra: Az üzleti szabályok nem engedélyezik az olyan áremeléseket, amelyek egy termék árának több mint duplájára emelkednek (kattintson ide a teljes méretű kép megtekintéséhez)
Megjegyzés:
Ideális esetben az üzleti logikára vonatkozó szabályok át lesznek bontva a UpdateProduct metódus túlterheléséből és egy közös módszerbe. Az olvasóra van bízva ez a gyakorlat.
Összefoglalás
Beszúrási, frissítési és törlési műveletek során mind az adatweb-vezérlő, mind az ObjectDataSource aktiválja az elő- és utószintű eseményeket, amelyek keretezik a tényleges műveleteket. Ahogy ebben az oktatóanyagban és az előzőben is láttuk, a szerkeszthető GridView használatakor a GridView eseményei RowUpdating aktiválódnak, majd az ObjectDataSource eseménye Updating következik, ahol a frissítési parancs az ObjectDataSource mögöttes objektumára kerül. A művelet befejezése után az ObjectDataSource eseménye Updated aktiválódik, amelyet a GridView eseménye RowUpdated követ.
Az előszintű eseményekhez eseménykezelőket hozhatunk létre a bemeneti paraméterek vagy a posztszintű események testreszabásához a művelet eredményeinek vizsgálatához és megválaszolásához. A posztszintű eseménykezelőket leggyakrabban arra használják, hogy észleljék, történt-e kivétel a művelet során. A kivételekkel szemben ezek a posztszintű eseménykezelők önállóan is kezelhetik a kivételt. Ebben az oktatóanyagban egy rövid hibaüzenet megjelenítésével láttuk, hogyan kezelhető egy ilyen kivétel.
A következő oktatóanyagban bemutatjuk, hogyan csökkenthetjük az adatformázási problémákból (például negatív UnitPricebeírásából) eredő kivételek valószínűségét. Pontosabban azt vizsgáljuk meg, hogyan adhat hozzá érvényesítési vezérlőket a szerkesztési és beszúrási felületekhez.
Boldog programozást!
Tudnivalók a szerzőről
Scott Mitchell, hét ASP/ASP.NET-könyv szerzője és a 4GuysFromRolla.com alapítója, 1998 óta dolgozik a Microsoft webtechnológiáival. Scott független tanácsadóként, edzőként és íróként dolgozik. Legújabb könyve Sams Tanuld meg ASP.NET 2.0 24 óra alatt. Ő itt elérhető mitchell@4GuysFromRolla.com.
Külön köszönet
Ezt az oktatóanyag-sorozatot sok hasznos véleményező áttekintette. Az oktatóanyag vezető véleményezője Liz Shulok volt. Szeretné áttekinteni a közelgő MSDN-cikkeimet? Ha igen, írj egy sort a mitchell@4GuysFromRolla.com-ra.