Sdílet prostřednictvím


Zpracování výjimek na úrovni knihoven BLL a DAL na stránce ASP.NET (VB)

Scott Mitchell

Stáhnout PDF

V tomto kurzu se dozvíte, jak zobrazit popisnou a informativní chybovou zprávu, pokud během operace vložení, aktualizace nebo odstranění webového ovládacího prvku ASP.NET dat dojde k výjimce.

Úvod

Práce s daty z webové aplikace ASP.NET pomocí vrstvené aplikační architektury zahrnuje následující tři obecné kroky:

  1. Určete, jakou metodu vrstvy obchodní logiky je potřeba vyvolat a jaké hodnoty parametrů se mají předat. Hodnoty parametrů můžou být pevně kódované, programově přiřazené nebo vstupy zadané uživatelem.
  2. Vyvolá metodu.
  3. Zpracujte výsledky. Při volání metody BLL, která vrací data, to může zahrnovat vazbu dat na datový webový ovládací prvek. U metod BLL, které upravují data, to může zahrnovat provedení určité akce na základě návratové hodnoty nebo řádné zpracování jakékoli výjimky, která vznikla v kroku 2.

Jak jsme viděli v předchozím kurzu, ovládací prvky ObjectDataSource a data Web poskytují body rozšiřitelnosti pro kroky 1 a 3. GridView například aktivuje svou RowUpdating událost před přiřazením hodnot polí do kolekce ObjectDataSource UpdateParameters ; jeho RowUpdated událost je vyvolána po dokončení operace ObjectDataSource.

Už jsme prozkoumali události, které se aktivují během kroku 1, a zjistili jsme, jak se dají použít k přizpůsobení vstupních parametrů nebo zrušení operace. V tomto kurzu obrátíme pozornost na události, které se aktivují po dokončení operace. Pomocí těchto obslužných rutin událostí po úrovni můžeme mimo jiné určit, jestli během operace došlo k výjimce, a elegantně ji zpracovat tak, že na obrazovce zobrazíme popisnou a informativní chybovou zprávu místo výchozího nastavení standardní stránky ASP.NET výjimky.

Pro ilustraci práce s těmito událostmi po úrovni vytvoříme stránku, která obsahuje seznam produktů v upravitelném zobrazení GridView. Pokud při aktualizaci produktu dojde k výjimce, zobrazí se na stránce ASP.NET nad objektem GridView krátká zpráva s vysvětlením, že došlo k problému. Pusťme se do toho.

Krok 1: Vytvoření upravitelného zobrazení GridView produktů

V předchozím kurzu jsme vytvořili upravitelný objekt GridView s pouhými dvěma poli ProductName a UnitPrice. To vyžadovalo vytvoření dalšího přetížení pro metodu ProductsBLL třídy UpdateProduct , která přijímala pouze tři vstupní parametry (název produktu, jednotkovou cenu a ID) na rozdíl od parametru pro každé pole produktu. V tomto kurzu si tuto techniku znovu procvičme a vytvoříme upravitelné zobrazení GridView, které zobrazuje název produktu, množství na jednotku, jednotkovou cenu a jednotky na skladě, ale umožňuje úpravu pouze názvu, jednotkové ceny a jednotek na skladě.

K tomuto scénáři budeme potřebovat další přetížení UpdateProduct metody, které přijímá čtyři parametry: název produktu, jednotkovou cenu, skladové jednotky a ID. Do třídy ProductsBLL přidejte následující metodu:

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateProduct _
    (ByVal productName As String, ByVal unitPrice As Nullable(Of Decimal), _
ByVal unitsInStock As Nullable(Of Short), ByVal productID As Integer) As Boolean
    Dim products As Northwind.ProductsDataTable = _
        Adapter.GetProductByProductID(productID)
    If products.Count = 0 Then
        Return False
    End If
    Dim product As Northwind.ProductsRow = products(0)
    product.ProductName = productName
    If Not unitPrice.HasValue Then
        product.SetUnitPriceNull()
    Else
        product.UnitPrice = unitPrice.Value
    End If
    If Not unitsInStock.HasValue Then
        product.SetUnitsInStockNull()
    Else
        product.UnitsInStock = unitsInStock.Value
    End If
    Dim rowsAffected As Integer = Adapter.Update(product)
    Return rowsAffected = 1
End Function

Po dokončení této metody jsme připraveni vytvořit stránku ASP.NET, která umožňuje upravit tato čtyři konkrétní pole produktů. ErrorHandling.aspx Otevřete stránku ve EditInsertDelete složce a přidejte na stránku objekt GridView prostřednictvím Designer. Vytvořte vazbu objektu GridView na nový ObjectDataSource, mapování Select() metody na metodu ProductsBLL třídy GetProducts() a metodu Update() na UpdateProduct právě vytvořené přetížení.

Použití přetížení metody UpdateProduct, která přijímá čtyři vstupní parametry

Obrázek 1: Použití UpdateProduct přetížení metody, která přijímá čtyři vstupní parametry (kliknutím zobrazíte obrázek v plné velikosti)

Tím se vytvoří ObjectDataSource s kolekcí UpdateParameters se čtyřmi parametry a Objekt GridView s polem pro každé pole produktu. Deklarativní značka ObjectDataSource přiřadí OldValuesParameterFormatString vlastnost hodnotu original_{0}, což způsobí výjimku, protože naše třídy BLL neočekávají předání vstupního parametru s názvem original_productID . Nezapomeňte toto nastavení úplně odebrat z deklarativní syntaxe (nebo ho nastavit na výchozí hodnotu). {0}

Dále parepište Objekt GridView tak, aby zahrnoval pouze ProductNameobjekty , QuantityPerUnitUnitPrice, a UnitsInStock BoundFields. Nebojte se také použít jakékoli formátování na úrovni pole, které považujete za nezbytné (například změnu HeaderText vlastností).

V předchozím kurzu jsme se podívali na to, jak formátovat UnitPrice BoundField jako měnu v režimu jen pro čtení i v režimu úprav. Pojďme to samé udělat tady. Vzpomeňte si, že to vyžaduje nastavení vlastnosti BoundField DataFormatString na {0:c}, jeho HtmlEncode vlastnost na falsea jeho ApplyFormatInEditMode na true, jak je znázorněno na obrázku 2.

Konfigurace pole BoundField UnitPrice tak, aby se zobrazovala jako měna

Obrázek 2: Konfigurace UnitPrice pole BoundField tak, aby se zobrazovala jako měna (kliknutím zobrazíte obrázek v plné velikosti)

Formátování objektu UnitPrice jako měny v rozhraní pro úpravy vyžaduje vytvoření obslužné rutiny události pro událost GridView RowUpdating , která parsuje řetězec ve formátu měny na decimal hodnotu. Vzpomeňte RowUpdating si, že obslužná rutina události z posledního kurzu také zkontrolovala, aby se zajistilo, že uživatel zadal UnitPrice hodnotu. V tomto kurzu však uživateli umožníme vynechat cenu.

Protected Sub GridView1_RowUpdating(ByVal sender As Object, _
    ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) _
    Handles GridView1.RowUpdating
    If e.NewValues("UnitPrice") IsNot Nothing Then
        e.NewValues("UnitPrice") = _
            Decimal.Parse(e.NewValues("UnitPrice").ToString(), _
            System.Globalization.NumberStyles.Currency)
    End If

Naše zobrazení GridView obsahuje QuantityPerUnit BoundField, ale toto BoundField by mělo být pouze pro účely zobrazení a uživatel by ho neměl upravovat. Pokud to chcete uspořádat, jednoduše nastavte vlastnost BoundFields ReadOnly na true.

Nastavit QuantityPerUnit BoundField jen pro čtení

Obrázek 3: Vytvoření QuantityPerUnit Read-Only BoundField (kliknutím zobrazíte obrázek v plné velikosti)

Nakonec zaškrtněte políčko Povolit úpravy u inteligentní značky GridView. Po dokončení těchto kroků ErrorHandling.aspx by Designer stránky měly vypadat podobně jako na obrázku 4.

Odeberte všechna kromě potřebných boundfields a zaškrtněte políčko Povolit úpravy.

Obrázek 4: Odeberte všechna, ale potřebná boundfields a zaškrtněte políčko Povolit úpravy (kliknutím zobrazíte obrázek v plné velikosti)

V tomto okamžiku máme seznam polí , , a všech produktůProductName. Upravit je ale možné pouze ProductNamepole , UnitPricea UnitsInStock .UnitsInStockUnitPriceQuantityPerUnit

Uživatelé teď můžou snadno upravovat názvy produktů, ceny a jednotky v polích Sklad.

Obrázek 5: Uživatelé teď můžou snadno upravovat názvy produktů, ceny a jednotky v polích zásob (kliknutím zobrazíte obrázek v plné velikosti)

Krok 2: Řádné zpracování výjimek DAL-Level

Zatímco náš upravitelný GridView funguje skvěle, když uživatelé zadávají právní hodnoty pro název, cenu a jednotky upraveného produktu na skladě, zadáním neplatných hodnot dojde k výjimce. Například vynechání ProductName hodnoty způsobí vyvolání NoNullAllowedException , protože ProductName vlastnost ve ProductsRow třídě má svou AllowDBNull vlastnost nastavenou na false; pokud je databáze mimo provoz, SqlException bude objekt TableAdapter vyvolán při pokusu o připojení k databázi. Bez provedení jakékoli akce se tyto výjimky zobrazí z vrstvy přístupu k datům do vrstvy obchodní logiky, pak na stránku ASP.NET a nakonec do modulu runtime ASP.NET.

V závislosti na tom, jak je vaše webová aplikace nakonfigurovaná a jestli ji navštěvujete z localhostaplikace , může neošetřená výjimka vést buď k obecné chybové stránce serveru, k podrobné zprávě o chybách nebo k uživatelsky přívětivé webové stránce. Další informace o tom, jak modul runtime ASP.NET reaguje na nezachycenou výjimku, najdete v tématu Zpracování chyb webové aplikace v ASP.NET a elementu customErrors .

Obrázek 6 znázorňuje obrazovku při pokusu o aktualizaci produktu bez zadání ProductName hodnoty. Toto je výchozí podrobná zpráva o chybách, která se zobrazí při procházení .localhost

Při vynechání názvu produktu se zobrazí podrobnosti o výjimce.

Obrázek 6: Vynechání názvu produktu zobrazí podrobnosti o výjimce (kliknutím zobrazíte obrázek v plné velikosti)

I když jsou takové podrobnosti o výjimce užitečné při testování aplikace, prezentování takové obrazovky koncovému uživateli tváří v tvář výjimce není ideální. Koncový uživatel pravděpodobně neví, co NoNullAllowedException je nebo proč k němu došlo. Lepším přístupem je prezentovat uživateli uživatelsky přívětivější zprávu vysvětlující, že při pokusu o aktualizaci produktu došlo k problémům.

Pokud při provádění operace dojde k výjimce, události po úrovni v ovládacím prvku ObjectDataSource a data Web poskytují prostředky k jeho zjištění a zrušení výjimky z probublávání až do modulu runtime ASP.NET. V našem příkladu vytvoříme obslužnou rutinu události pro událost GridView RowUpdated , která určí, jestli se aktivovala výjimka, a pokud ano, zobrazí podrobnosti o výjimce v ovládacím prvku Label Web.

Začněte tím, že na stránku ASP.NET přidáte popisek, nastavíte jeho ID vlastnost na ExceptionDetails a vymažete jeho Text vlastnost. Pokud chcete na tuto zprávu nakreslit oko uživatele, nastavte jeho CssClass vlastnost na Warning, což je třída CSS, kterou jsme přidali do Styles.css souboru v předchozím kurzu. Vzpomeňte si, že tato třída CSS způsobí, že se text popisku zobrazí červeným, kurzívou, tučným a extra velkým písmem.

Přidání webového ovládacího prvku Label na stránku

Obrázek 7: Přidání webového ovládacího prvku Popisek na stránku (kliknutím zobrazíte obrázek v plné velikosti)

Vzhledem k tomu, že chceme, aby byl tento ovládací prvek Label Web viditelný pouze okamžitě po vytvoření výjimky, nastavte jeho Visible vlastnost v obslužné rutině Page_Load události na hodnotu false:

Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    ExceptionDetails.Visible = False
End Sub

S tímto kódem bude mít ovládací prvek na první stránce ExceptionDetails nastavenou falsevlastnost Visible na . Tváří v tvář výjimce na úrovni DAL nebo BLL, kterou můžeme zjistit v obslužné rutině události GridView RowUpdated , nastavíme ExceptionDetails vlastnost ovládacího prvku Visible na true. Vzhledem k tomu, že obslužné rutiny událostí webového Page_Load ovládacího prvku se vyskytují po obslužné rutině události v životním cyklu stránky, zobrazí se popisek. Při dalším postbacku však obslužná rutina Page_Load události vrátí Visible vlastnost zpět na falsea znovu ji skryje ze zobrazení.

Poznámka

Případně bychom mohli odebrat nutnost nastavení ExceptionDetails vlastnosti ovládacího prvku Visible v Page_Load souboru tím, že přiřadíme jeho Visible vlastnost false v deklarativní syntaxi a zakážeme jeho stav zobrazení (nastavíme jeho EnableViewState vlastnost na false). Tento alternativní přístup použijeme v budoucím kurzu.

Po přidání ovládacího prvku Label je naším dalším krokem vytvoření obslužné rutiny události pro událost GridView RowUpdated . V Designer vyberte GridView, přejděte na okno Vlastnosti a klikněte na ikonu blesku se seznamem událostí GridView. Již by tam měla být položka pro událost GridView RowUpdating , protože jsme vytvořili obslužnou rutinu události pro tuto událost dříve v tomto kurzu. Vytvořte obslužnou rutinu události také pro událost RowUpdated .

Vytvoření obslužné rutiny události pro událost RowUpdated objektu GridView

Obrázek 8: Vytvoření obslužné rutiny události pro událost GridView RowUpdated

Poznámka

Obslužnou rutinu události můžete také vytvořit prostřednictvím rozevíracích seznamů v horní části souboru třídy kódu na pozadí. V rozevíracím seznamu vlevo vyberte GridView a RowUpdated v pravé části vyberte událost GridView.

Při vytváření této obslužné rutiny události se do třídy kódu na pozadí stránky ASP.NET přidá následující kód:

Protected Sub GridView1_RowUpdated(ByVal sender As Object, _
    ByVal e As System.Web.UI.WebControls.GridViewUpdatedEventArgs) _
    Handles GridView1.RowUpdated
End Sub

Druhý vstupní parametr obslužné rutiny události je objekt typu GridViewUpdatedEventArgs, který má tři vlastnosti, které jsou zajímavé pro zpracování výjimek:

  • Exception odkaz na vyvolanou výjimku; Pokud nebyla vyvolána žádná výjimka, bude mít tato vlastnost hodnotu null
  • ExceptionHandled Logická hodnota, která označuje, jestli byla výjimka zpracována v RowUpdated obslužné rutině události. Pokud false (výchozí), výjimka se znovu vyvolá a překryje až do modulu runtime ASP.NET
  • KeepInEditMode pokud je nastavený na true upravený řádek GridView, zůstane v režimu úprav. Pokud false (výchozí), vrátí se řádek GridView zpět do režimu jen pro čtení.

Náš kód by pak měl zkontrolovat, jestli Exception není null, což znamená, že při provádění operace byla vyvolána výjimka. V takovém případě chceme:

  • Zobrazení uživatelsky přívětivé zprávy v popisku ExceptionDetails
  • Označení, že výjimka byla zpracována
  • Zachování řádku GridView v režimu úprav

Následující kód dosahuje těchto cílů:

Protected Sub GridView1_RowUpdated(ByVal sender As Object, _
    ByVal e As System.Web.UI.WebControls.GridViewUpdatedEventArgs) _
    Handles GridView1.RowUpdated
    If e.Exception IsNot Nothing Then
        ExceptionDetails.Visible = True
        ExceptionDetails.Text = "There was a problem updating the product. "
        If e.Exception.InnerException IsNot Nothing Then
            Dim inner As Exception = e.Exception.InnerException
            If TypeOf inner Is System.Data.Common.DbException Then
                ExceptionDetails.Text &= _
                "Our database is currently experiencing problems." & _
                "Please try again later."
            ElseIf TypeOf inner _
             Is System.Data.NoNullAllowedException Then
                ExceptionDetails.Text += _
                    "There are one or more required fields that are missing."
            ElseIf TypeOf inner Is ArgumentException Then
                Dim paramName As String = CType(inner, ArgumentException).ParamName
                ExceptionDetails.Text &= _
                    String.Concat("The ", paramName, " value is illegal.")
            ElseIf TypeOf inner Is ApplicationException Then
                ExceptionDetails.Text += inner.Message
            End If
        End If
        e.ExceptionHandled = True
        e.KeepInEditMode = True
    End If
End Sub

Tato obslužná rutina události začíná kontrolou, jestli e.Exception je null. Pokud tomu tak není, ExceptionDetails vlastnost Label je Visible nastavená na true a vlastnost Text "Při aktualizaci produktu došlo k potížím". Podrobnosti o skutečné výjimce, která byla vyvolán, se nacházejí ve vlastnosti objektu e.ExceptionInnerException . Tato vnitřní výjimka se prověří a pokud je konkrétního typu, připojí se k ExceptionDetails vlastnosti Label Text další užitečná zpráva. ExceptionHandled Nakonec jsou vlastnosti a KeepInEditMode nastaveny na truehodnotu .

Obrázek 9 ukazuje snímek obrazovky této stránky při vynechání názvu produktu; Obrázek 10 ukazuje výsledky při zadávání neplatné UnitPrice hodnoty (-50).

ProductName BoundField musí obsahovat hodnotu.

Obrázek 9: BoundField ProductName musí obsahovat hodnotu (kliknutím zobrazíte obrázek v plné velikosti)

Záporné hodnoty UnitPrice nejsou povoleny.

Obrázek 10: Záporné UnitPrice hodnoty nejsou povolené (kliknutím zobrazíte obrázek v plné velikosti)

Nastavením e.ExceptionHandled vlastnosti na truehodnotu byla obslužná RowUpdated rutina události označena, že zpracovala výjimku. Proto se výjimka nebude šířit až do modulu runtime ASP.NET.

Poznámka

Obrázky 9 a 10 ukazují elegantní způsob zpracování výjimek vyvolaných kvůli neplatnému vstupu uživatele. V ideálním případě se ale takový neplatný vstup nikdy nedostane do vrstvy obchodní logiky, protože stránka ASP.NET by měla před vyvoláním ProductsBLL metody třídy UpdateProduct zajistit, aby vstupy uživatele byly platné. V dalším kurzu se dozvíte, jak přidat ověřovací ovládací prvky do rozhraní pro úpravy a vkládání, abychom zajistili, že data odeslaná do vrstvy obchodní logiky odpovídají obchodním pravidlům. Ověřovací ovládací prvky nejen brání vyvolání UpdateProduct metody, dokud nebudou data zadaná uživatelem platná, ale také poskytují informativnější uživatelské prostředí pro identifikaci problémů se zadáváním dat.

Krok 3: Řádné zpracování výjimek BLL-Level

Při vkládání, aktualizaci nebo odstraňování dat může vrstva přístupu k datům vyvolat výjimku tváří v tvář chybě související s daty. Databáze může být offline, požadovaný sloupec tabulky databáze nemusí mít zadanou hodnotu nebo došlo k porušení omezení na úrovni tabulky. Kromě výjimek výhradně souvisejících s daty může vrstva obchodní logiky používat výjimky k označení, kdy došlo k porušení obchodních pravidel. Například v kurzu Vytvoření vrstvy obchodní logiky jsme do původního UpdateProduct přetížení přidali kontrolu obchodních pravidel. Konkrétně pokud uživatel označoval produkt jako ukončený, požadovali jsme, aby produkt nebyl jediný, který mu poskytl jeho dodavatel. Pokud byla tato podmínka porušena, došlo k ApplicationException vyvolání.

UpdateProduct Pro přetížení vytvořené v tomto kurzu přidáme obchodní pravidlo, které zakážeUnitPrice, aby pole bylo nastaveno na novou hodnotu, která je více než dvakrát vyšší než původní UnitPrice hodnota. Chcete-li toho dosáhnout, upravte UpdateProduct přetížení tak, aby provedlo tuto kontrolu a vyvolá chybu ApplicationException , pokud je pravidlo porušeno. Aktualizovaná metoda následuje:

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Update, True)> _
    Public Function UpdateProduct(ByVal productName As String, _
    ByVal unitPrice As Nullable(Of Decimal), ByVal unitsInStock As Nullable(Of Short), _
    ByVal productID As Integer) As Boolean
    Dim products As Northwind.ProductsDataTable = Adapter.GetProductByProductID(productID)
    If products.Count = 0 Then
        Return False
    End If
    Dim product As Northwind.ProductsRow = products(0)
    If unitPrice.HasValue AndAlso Not product.IsUnitPriceNull() Then
        If unitPrice > product.UnitPrice * 2 Then
            Throw New ApplicationException( _
                "When updating a product price," & _
                " the new price cannot exceed twice the original price.")
        End If
    End If
    product.ProductName = productName
    If Not unitPrice.HasValue Then
        product.SetUnitPriceNull()
    Else
        product.UnitPrice = unitPrice.Value
    End If
    If Not unitsInStock.HasValue Then
        product.SetUnitsInStockNull()
    Else
        product.UnitsInStock = unitsInStock.Value
    End If
    Dim rowsAffected As Integer = Adapter.Update(product)
    Return rowsAffected = 1
End Function

Při této změně způsobí ApplicationException jakákoli aktualizace cen, která je více než dvojnásobek stávající ceny, vyvolá vyvolání. Stejně jako výjimka vyvolaná z DAL, může být tato zvýšená ApplicationException BLL rozpoznána a zpracována v obslužné rutině události GridView RowUpdated . Ve skutečnosti RowUpdated kód obslužné rutiny události, jak je napsaný, tuto výjimku správně rozpozná a zobrazí ApplicationExceptionhodnotu vlastnosti .Message Obrázek 11 ukazuje snímek obrazovky, když se uživatel pokusí aktualizovat cenu Chai na 50,00 USD, což je více než dvojnásobek aktuální ceny 19,95 USD.

Obchodní pravidla neumožňují zvýšení cen, které více než zdvojnásobí cenu produktu.

Obrázek 11: Obchodní pravidla neumožňují zvýšení ceny, které je vyšší než dvojnásobek ceny produktu (kliknutím zobrazíte obrázek v plné velikosti)

Poznámka

V ideálním případě by se pravidla obchodní logiky refaktorovala z UpdateProduct přetížení metod do běžné metody. Toto je ponecháno jako cvičení pro čtenáře.

Souhrn

Při vkládání, aktualizaci a odstraňování operací zahrnoval ovládací prvek web dat i ObjectDataSource události před a po úrovni, které zarezervují skutečnou operaci. Jak jsme viděli v tomto kurzu a předchozím, při práci s upravitelným objektem GridView se aktivuje událost GridView RowUpdating následovaná událostí ObjectDataSource Updating , v tomto okamžiku se provede příkaz update na podkladový objekt ObjectDataSource. Po dokončení operace se aktivuje událost ObjectDataSource Updated následovaná událostí GridView RowUpdated .

Můžeme vytvořit obslužné rutiny událostí pro události před úrovní, abychom mohli přizpůsobit vstupní parametry nebo pro události po úrovni, abychom mohli zkontrolovat výsledky operace a reagovat na ně. Obslužné rutiny událostí po úrovni se nejčastěji používají ke zjištění, jestli během operace došlo k výjimce. V případě výjimky můžou tyto obslužné rutiny událostí po úrovni volitelně zpracovávat výjimku samostatně. V tomto kurzu jsme viděli, jak takovou výjimku zpracovat zobrazením popisné chybové zprávy.

V dalším kurzu se dozvíte, jak zmenšit pravděpodobnost výjimek vyplývajících z problémů s formátováním dat (například zadání záporné UnitPricehodnoty ). Konkrétně se podíváme na to, jak přidat ověřovací ovládací prvky do rozhraní pro úpravy a vkládání.

Šťastné programování!

O autorovi

Scott Mitchell, autor sedmi knih o ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, školitel a spisovatel. Jeho nejnovější kniha je Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Můžete ho najít na mitchell@4GuysFromRolla.comadrese . nebo prostřednictvím jeho blogu, který najdete na http://ScottOnWriting.NETadrese .

Zvláštní poděkování

Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Hlavní kontrolorka tohoto kurzu byla Liz Shulok. Chcete si projít moje nadcházející články na WEBU MSDN? Pokud ano, dejte mi čáru na mitchell@4GuysFromRolla.comadresu .