Dela via


Skapa ett dataåtkomstlager (VB)

av Scott Mitchell

Ladda ned PDF

I den här självstudien börjar vi från början och skapar Data Access Layer (DAL), med hjälp av typerade datauppsättningar, för att få åtkomst till informationen i en databas.

Inledning

Som webbutvecklare handlar våra liv om att arbeta med data. Vi skapar databaser för att lagra data, kod för att hämta och ändra dem samt webbsidor för att samla in och sammanfatta dem. Det här är den första handledningen i en lång serie som utforskar tekniker för att implementera dessa vanliga mönster i ASP.NET 2.0. Vi börjar med att skapa en programvaruarkitektur som består av ett dataåtkomstlager (DAL) med hjälp av typade datauppsättningar, ett BLL (Business Logic Layer) som tillämpar anpassade affärsregler och ett presentationslager som består av ASP.NET sidor som delar en gemensam sidlayout. När det här grundarbetet för serverdelen har lagts till övergår vi till rapportering och visar hur du visar, sammanfattar, samlar in och validerar data från ett webbprogram. De här självstudierna är inriktade på att vara koncisa och ge stegvisa instruktioner med massor av skärmdumpar som vägleder dig genom processen visuellt. Varje självstudiekurs är tillgänglig i C#- och Visual Basic-versioner och innehåller en nedladdning av den fullständiga koden som används. (Den här första handledningen är ganska lång, men resten presenteras i mycket mer lättsmälta delar.)

För de här självstudierna använder vi en Microsoft SQL Server 2005 Express Edition-version av Northwind-databasen som finns i App_Data katalogen. Förutom databasfilen App_Data innehåller mappen även SQL-skripten för att skapa databasen, om du vill använda en annan databasversion. Om du använder en annan SQL Server-version av Northwind-databasen måste du uppdatera NORTHWNDConnectionString inställningen i programmets Web.config fil. Webbprogrammet skapades med Visual Studio 2005 Professional Edition som ett filsystembaserat webbplatsprojekt. Alla handledningar fungerar dock lika bra med den kostnadsfria versionen av Visual Studio 2005, Visual Web Developer.

I den här självstudien börjar vi från början och skapar Data Access Layer (DAL), följt av att skapa Business Logic Layer (BLL) i den andra självstudien och arbeta med sidlayout och navigering i den tredje. Handledningarna efter den tredje kommer att bygga vidare på den grund som lades i de tre första. Vi har mycket att ta upp i den här första självstudien, så starta Visual Studio och kom igång!

Steg 1: Skapa ett webbprojekt och ansluta till databasen

Innan vi kan skapa vårt dal-lager (Data Access Layer) måste vi först skapa en webbplats och konfigurera databasen. Börja med att skapa en ny filsystembaserad ASP.NET webbplats. Det gör du genom att gå till menyn Arkiv och välja Ny webbplats och visa dialogrutan Ny webbplats. Välj mallen ASP.NET webbplats, ange listrutan Plats till Filsystem, välj en mapp för att placera webbplatsen och ange språket till Visual Basic.

Skapa en ny fil System-Based webbplats

Bild 1: Skapa en ny fil System-Based webbplats (Klicka om du vill visa en bild i full storlek)

Då skapas en ny webbplats med en Default.aspx ASP.NET sida, en App_Data mapp och en Web.config fil.

När webbplatsen har skapats är nästa steg att lägga till en referens till databasen i Visual Studio Server Explorer. Genom att lägga till en databas i ServerUtforskaren kan du lägga till tabeller, lagrade procedurer, vyer och så vidare från Visual Studio. Du kan också visa tabelldata eller skapa egna frågor antingen för hand eller grafiskt via Query Builder. När vi skapar Typed DataSets för DAL måste vi dessutom peka Visual Studio på den databas som de typerade datauppsättningarna ska konstrueras från. Vi kan ange den här anslutningsinformationen vid den tidpunkten, men Visual Studio fyller automatiskt i en listruta över de databaser som redan har registrerats i Server Explorer.

Stegen för att lägga till Northwind-databasen i Server Explorer beror på om du vill använda SQL Server 2005 Express Edition-databasen i App_Data mappen eller om du har en Microsoft SQL Server 2000- eller 2005-databasserverkonfiguration som du vill använda i stället.

Använda en databas i mappenApp_Data

Om du inte har en SQL Server 2000- eller 2005-databasserver att ansluta till, eller om du helt enkelt vill undvika att behöva lägga till databasen till en databasserver, kan du använda SQL Server 2005 Express Edition-versionen av Northwind-databasen som finns i den nedladdade webbplatsens App_Data mapp (NORTHWND.MDF).

En databas som placeras i App_Data mappen läggs automatiskt till i ServerUtforskaren. Förutsatt att du har SQL Server 2005 Express Edition installerat på datorn bör du se en nod med namnet NORTHWND. MDF i Server Explorer, som du kan expandera och utforska dess tabeller, vyer, lagrade procedur och så vidare (se bild 2).

Mappen App_Data kan också innehålla Microsoft Access-filer .mdb , som, precis som deras SQL Server-motsvarigheter, automatiskt läggs till i Server Explorer. Om du inte vill använda något av SQL Server-alternativen kan du alltid installera Northwind Traders databas och appar och släppa dem i App_Data katalogen. Tänk dock på att Access-databaser inte är lika funktionsrika som SQL Server och inte är utformade för att användas i webbplatsscenarier. Dessutom kommer ett par av de över 35 handledningarna att använda vissa funktioner på databasnivå som inte stöds av Access.

Ansluta till databasen i en Microsoft SQL Server 2000- eller 2005-databasserver

Du kan också ansluta till en Northwind-databas som är installerad på en databasserver. Om databasservern inte redan har Northwind-databasen installerad måste du först lägga till den i databasservern genom att köra installationsskriptet som ingår i nedladdningen av den här självstudien.

När du har installerat databasen går du till Serverutforskaren i Visual Studio, högerklickar på noden Dataanslutningar och väljer Lägg till anslutning. Om du inte ser serverutforskaren går du till View/Server Explorer eller trycker på Ctrl+Alt+S. Då visas dialogrutan Lägg till anslutning, där du kan ange vilken server du vill ansluta till, autentiseringsinformationen och databasnamnet. När du har konfigurerat informationen om databasanslutningen och klickat på KNAPPEN OK läggs databasen till som en nod under noden Dataanslutningar. Du kan expandera databasnoden för att utforska dess tabeller, vyer, lagrade procedurer och så vidare.

Lägga till en anslutning till databasserverns Northwind-databas

Bild 2: Lägg till en anslutning till databasserverns Northwind-databas

Steg 2: Skapa dataåtkomstskiktet

När du arbetar med data är ett alternativ att bädda in dataspecifik logik direkt i presentationslagret (i ett webbprogram utgör de ASP.NET sidorna presentationslagret). Detta kan ske i form av att skriva ADO.NET kod i ASP.NET-sidans koddel eller med hjälp av SqlDataSource-kontrollen från markeringsdelen. I båda fallen är den här metoden nära kopplad till dataåtkomstlogiken och presentationslagret. Den rekommenderade metoden är dock att separera dataåtkomstlogik från presentationslagret. Det här separata lagret kallas för Data Access Layer, DAL för kort och implementeras vanligtvis som ett separat klassbiblioteksprojekt. Fördelarna med den här skiktade arkitekturen är väldokumenterade (se avsnittet "Ytterligare läsningar" i slutet av den här självstudien för information om dessa fördelar) och är den metod vi kommer att använda i den här serien.

All kod som är specifik för den underliggande datakällan, till exempel att skapa en anslutning till databasen, utfärda SELECT, INSERT, UPDATEoch DELETE kommandon och så vidare ska finnas i DAL. Presentationslagret bör inte innehålla några referenser till sådan dataåtkomstkod, utan i stället göra anrop till DAL för alla databegäranden. Dataåtkomstlager innehåller vanligtvis metoder för att komma åt underliggande databasdata. Northwind-databasen har till exempel tabellerna Products och Categories som registrerar produkterna till salu och de kategorier de tillhör. I vår DAL kommer vi att ha metoder som:

  • GetCategories(), som returnerar information om alla kategorier
  • GetProducts(), som returnerar information om alla produkter
  • GetProductsByCategoryID(categoryID), som returnerar alla produkter som tillhör en angiven kategori
  • GetProductByProductID(productID), som returnerar information om en viss produkt

Dessa metoder, när de anropas, ansluter till databasen, utfärdar lämplig fråga och returnerar resultaten. Hur vi returnerar dessa resultat är viktigt. Dessa metoder kan enkelt returnera en DataSet eller DataReader som fylls i av databasfrågan, men helst bör dessa resultat returneras med hjälp av starkt typade objekt. Ett starkt typat objekt är ett vars schema är strikt definierat vid kompileringstillfället, medan motsatsen, ett löst typat objekt, är ett vars schema inte är känt förrän vid körning.

Till exempel är DataReader och DataSet (som standard) löst skrivna objekt eftersom deras schema definieras av de kolumner som returneras av databasfrågan som används för att fylla i dem. För att få åtkomst till en viss kolumn från en löst typad DataTable måste vi använda syntax som: DataTable.Rows(index)("columnName"). DataTables lösa typning i det här exemplet visas av att vi måste komma åt kolumnnamnet genom en sträng eller ett ordningsindex. En starkt typad DataTable, å andra sidan, kommer att ha var och en av sina kolumner implementerade som egenskaper, vilket resulterar i kod som ser ut så här: DataTable.Rows(index).columnName.

Utvecklare kan antingen skapa egna anpassade affärsobjekt eller använda Typed DataSets för att returnera starkt skrivna objekt. Ett affärsobjekt implementeras av utvecklaren som en klass vars egenskaper vanligtvis återspeglar kolumnerna i den underliggande databastabellen som affärsobjektet representerar. En Typed DataSet är en klass som genereras åt dig av Visual Studio baserat på ett databasschema och vars medlemmar är starkt skrivna enligt det här schemat. Själva Typed DataSet består av klasser som utökar klasserna ADO.NET DataSet, DataTable och DataRow. Förutom starkt skrivna DataTables inkluderar typade datauppsättningar nu även TableAdapters, som är klasser med metoder för att fylla i DataSet-datatabeller och sprida ändringar i DataTables tillbaka till databasen.

Anmärkning

Mer information om fördelarna och nackdelarna med att använda typade datauppsättningar jämfört med anpassade affärsobjekt finns i Designa komponenter på datanivå och Skicka data via nivåer.

Vi använder "starkt typade" DataSets för handledningarnas arkitektur. Bild 3 illustrerar arbetsflödet mellan de olika lagren i ett program som använder Typed DataSets.

All dataåtkomstkod förvisas till DAL

Bild 3: All dataåtkomstkod flyttas till DAL (klicka om du vill visa en bild i full storlek)

Skapa en typinskriven datauppsättning och ett tabellkort

För att börja skapa vår DAL börjar vi med att lägga till en Typed DataSet i vårt projekt. Det gör du genom att högerklicka på projektnoden i Solution Explorer och välja Lägg till ett nytt objekt. Välj alternativet DataSet i listan med mallar och ge den Northwind.xsdnamnet .

Välj att lägga till en ny datauppsättning i projektet

Bild 4: Välj att lägga till en ny datauppsättning i projektet (klicka om du vill visa en bild i full storlek)

När du har klickat på Lägg till väljer du Ja när du uppmanas att lägga till DataSet i App_Code mappen. Designern för den typerade datauppsättningen visas sedan och konfigurationsguiden TableAdapter startar, så att du kan lägga till din första TableAdapter i Typed DataSet.

En Typed DataSet fungerar som en starkt typad samling av data; den består av starkt typade DataTable-instanser, som i sin tur var och en består av starkt typade DataRow-instanser. Vi skapar en strikt typad DataTable för var och en av de underliggande databastabeller som vi behöver arbeta med i denna handledningsserie. Vi börjar med att skapa en DataTable för tabellen Products .

Tänk på att starkt skrivna DataTables inte innehåller någon information om hur du kommer åt data från den underliggande databastabellen. För att hämta data för att fylla i DataTable använder vi en TableAdapter-klass som fungerar som vårt dataåtkomstlager. För vår Products DataTable innehåller TableAdapter metoderna GetProducts(), GetProductByCategoryID(categoryID)och så vidare som vi anropar från presentationslagret. DataTables roll är att fungera som de starkt typade objekt som används för att överföra data mellan skikten.

Konfigurationsguiden för TableAdapter börjar med att uppmana dig att välja vilken databas du vill arbeta med. Listrutan visar dessa databaser i Serverutforskaren. Om du inte har lagt till Northwind-databasen i Serverutforskaren kan du klicka på knappen Ny anslutning för tillfället för att göra det.

Välj Northwind-databasen i Drop-Down-listan

Bild 5: Välj Northwind-databasen i Drop-Down-listan (Klicka om du vill visa en bild i full storlek)

När du har valt databasen och klickat på Nästa får du frågan om du vill spara anslutningssträngen Web.config i filen. Genom att spara anslutningssträngen undviker du att hårdkoda den i TableAdapter-klasserna, vilket förenklar saker om informationen om anslutningssträngen ändras i framtiden. Om du väljer att spara anslutningssträngen i konfigurationsfilen placeras den i <connectionStrings> avsnittet, som kan krypteras för bättre säkerhet eller ändras senare via den nya egenskapssidan ASP.NET 2.0 i IIS GUI Admin Tool, vilket är mer idealiskt för administratörer.

Spara anslutningssträngen till Web.config

Bild 6: Spara anslutningssträngen till Web.config (Klicka om du vill visa en bild i full storlek)

Därefter måste vi definiera schemat för den första starkt typade dataTabellen och ange den första metoden som TableAdapter ska använda när man fyller i det starkt typade DataSet. Dessa två steg utförs samtidigt genom att skapa en fråga som returnerar kolumnerna från tabellen som vi vill ska återspeglas i vår DataTable. I slutet av guiden ger vi denna sökfråga ett metodnamn. När det har utförts kan den här metoden anropas från presentationsskiktet. Metoden kör den definierade frågan och fyller i en starkt typad DataTable.

För att komma igång med att definiera SQL-frågan måste vi först ange hur vi vill att TableAdapter ska utfärda frågan. Vi kan använda en ad hoc SQL-instruktion, skapa en ny lagrad procedur eller använda en befintlig lagrad procedur. För de här handledningarna använder vi ad hoc SQL-instruktioner.

Utföra frågor mot data med hjälp av en ad-hoc SQL-instruktion

Bild 7: Fråga efter data med hjälp av en ad hoc SQL-instruktion (Klicka om du vill visa en bild i full storlek)

Nu kan vi skriva in SQL-frågan för hand. När du skapar den första metoden i TableAdapter vill du vanligtvis att frågan ska returnera de kolumner som måste uttryckas i motsvarande DataTable. Vi kan göra detta genom att skapa en fråga som returnerar alla kolumner och alla rader från Products tabellen:

Ange SQL-frågan i textrutan

Bild 8: Ange SQL-frågan i textrutan (Klicka om du vill visa en bild i full storlek)

Du kan också använda Query Builder och grafiskt konstruera frågan, enligt bild 9.

Skapa frågan grafiskt via frågeredigeraren

Bild 9: Skapa frågan grafiskt via frågeredigeraren (Klicka om du vill visa en bild i full storlek)

När du har skapat frågan, men innan du går vidare till nästa skärm klickar du på knappen Avancerade alternativ. I Webbplatsprojekt är "Generera infognings-, uppdaterings- och borttagningsinstruktioner" det enda avancerade alternativet som valts som standard. Om du kör den här guiden från ett klassbibliotek eller ett Windows-projekt väljs även alternativet "Använd optimistisk samtidighet". Låt alternativet "Använd optimistisk samtidighet" vara avmarkerat för tillfället. Vi kommer att undersöka optimistisk samtidighet i framtida handledningar.

Välj endast instruktionsalternativet Generera infoga, uppdatera och ta bort

Bild 10: Välj endast instruktionsalternativet Generera infoga, uppdatera och ta bort (Klicka om du vill visa en bild i full storlek)

När du har verifierat de avancerade alternativen klickar du på Nästa för att gå vidare till den sista skärmen. Här uppmanas vi att välja vilka metoder som ska läggas till i TableAdapter. Det finns två mönster för att fylla i data:

  • Fyll en DataTable med denna metod skapas en metod som tar in en DataTable som en parameter och fyller den baserat på resultaten av frågan. Klassen ADO.NET DataAdapter implementerar till exempel det här mönstret med sin Fill() metod.
  • Returnera en DataTable med den här metoden som metoden skapar och fyller datatabellen åt dig och returnerar den som metodernas returvärde.

Du kan låta TableAdapter implementera ett eller båda av dessa mönster. Du kan också byta namn på de metoder som anges här. Låt oss låta båda kryssrutorna vara markerade, även om vi bara använder det senare mönstret i de här självstudierna. Vi byter också namn på den ganska generiska GetData metoden till GetProducts.

Om markerad, skapar den sista kryssrutan "GenerateDBDirectMethods" metoder Insert(), Update() och Delete() för TableAdapter. Om du lämnar det här alternativet avmarkerat måste alla uppdateringar göras via TableAdapters enda Update() metod, som tar in Typed DataSet, en DataTable, en enda DataRow eller en matris med DataRows. (Om du har avmarkerat instruktionen "Generera infoga, uppdatera och ta bort" från de avancerade egenskaperna i bild 9 kommer den här kryssrutans inställning inte att ha någon effekt.) Låt den här kryssrutan vara markerad.

Ändra metodnamnet från GetData till GetProducts

Bild 11: Ändra metodnamnet från GetData till GetProducts (Klicka om du vill visa en bild i full storlek)

Slutför guiden genom att klicka på Avsluta. När guiden har stängts returneras vi till DataSet Designer som visar datatabellen som vi nyss skapade. Du kan se listan med kolumner i Products DataTable (ProductID, ProductNameoch så vidare) samt metoderna för ProductsTableAdapter (Fill() och GetProducts()).

Produkterna DataTable och ProductsTableAdapter har lagts till i typdatauppsättningen

Bild 12: DataTabellen Products och ProductsTableAdapter har lagts till i den inskrivna datamängden (Klicka om du vill visa en bild i full storlek)

Nu har vi en Typed DataSet med en enda DataTable (Northwind.Products) och en starkt typad DataAdapter-klass (NorthwindTableAdapters.ProductsTableAdapter) med en GetProducts() metod. Dessa objekt kan användas för att komma åt en lista över alla produkter från kod som:

Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
Dim products as Northwind.ProductsDataTable
products = productsAdapter.GetProducts()
For Each productRow As Northwind.ProductsRow In products
    Response.Write("Product: " & productRow.ProductName & "<br />")
Next

Den här koden krävde inte att vi skulle skriva en bit dataåtkomstspecifik kod. Vi behövde inte instansiera några ADO.NET klasser, vi behövde inte referera till några anslutningssträngar, SQL-frågor eller lagrade procedurer. TableAdapter tillhandahåller i stället dataåtkomstkoden på låg nivå åt oss.

Varje objekt som används i det här exemplet är också starkt typat, vilket gör att Visual Studio kan tillhandahålla IntelliSense och typkontroll vid kompilering. Och bäst av allt datatabeller som returneras av TableAdapter kan bindas till ASP.NET datawebbkontroller, till exempel GridView, DetailsView, DropDownList, CheckBoxList och flera andra. I följande exempel visas bindning av DataTable som returneras av GetProducts() metoden till ett GridView på bara tre knappa rader med kod i Page_Load händelsehanteraren.

AllProducts.aspx

<%@ Page Language="VB" AutoEventWireup="true" CodeFile="AllProducts.aspx.vb"
    Inherits="AllProducts" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>View All Products in a GridView</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>
            All Products</h1>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             CssClass="DataWebControlStyle">
               <HeaderStyle CssClass="HeaderStyle" />
               <AlternatingRowStyle CssClass="AlternatingRowStyle" />
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

AllProducts.aspx.vb

Imports NorthwindTableAdapters
Partial Class AllProducts
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles Me.Load
        Dim productsAdapter As New ProductsTableAdapter
        GridView1.DataSource = productsAdapter.GetProducts()
        GridView1.DataBind()
    End Sub
End Class

Listan över produkter visas i en GridView

Bild 13: Listan över produkter visas i en GridView (Klicka om du vill visa en bild i full storlek)

Det här exemplet krävde att vi skrev tre kodrader i händelsehanteraren för vår ASP.NET sida Page_Load , men i framtida självstudier ska vi undersöka hur du använder ObjectDataSource för att deklarativt hämta data från DAL. Med ObjectDataSource kommer vi inte att behöva skriva någon kod och får även stöd för sidindelning och sortering!

Steg 3: Lägga till parametriserade metoder i dataåtkomstskiktet

I det här läget har klassen ProductsTableAdapter bara en metod, GetProducts(), som returnerar alla produkter i databasen. Det är definitivt användbart att kunna arbeta med alla produkter, men det finns tillfällen då vi vill hämta information om en specifik produkt eller alla produkter som tillhör en viss kategori. Om du vill lägga till sådana funktioner i vårt dataåtkomstlager kan vi lägga till parametriserade metoder i TableAdapter.

Nu ska vi lägga till GetProductsByCategoryID(categoryID) metoden. Om du vill lägga till en ny metod i DAL går du tillbaka till DataSet Designer, högerklickar i ProductsTableAdapter avsnittet och väljer Lägg till fråga.

Right-Click på TableAdapter och välj Lägg till fråga

Bild 14: Right-Click på TableAdapter och Välj Lägg till fråga

Vi tillfrågas först om vi vill komma åt databasen med hjälp av en ad hoc SQL-instruktion eller en ny eller befintlig lagrad procedur. Nu väljer vi att använda en ad hoc SQL-instruktion igen. Därefter tillfrågas vi om vilken typ av SQL-fråga vi vill använda. Eftersom vi vill returnera alla produkter som tillhör en angiven kategori vill vi skriva en SELECT instruktion som returnerar rader.

Välj att skapa en SELECT-instruktion som returnerar rader

Bild 15: Välj att skapa en SELECT instruktion som returnerar rader (klicka om du vill visa en bild i full storlek)

Nästa steg är att definiera DEN SQL-fråga som används för att komma åt data. Eftersom vi bara vill returnera de produkter som tillhör en viss kategori använder jag samma SELECT instruktion från GetProducts(), men lägger till följande WHERE sats: WHERE CategoryID = @CategoryID. Parametern @CategoryID anger för guiden TableAdapter att metoden vi skapar kräver en indataparameter av motsvarande typ (dvs. ett heltal som kan vara null).

Ange en fråga för att endast returnera produkter i en angiven kategori

Bild 16: Ange en fråga för att endast returnera produkter i en angiven kategori (Klicka om du vill visa en bild i full storlek)

I det sista steget kan vi välja vilka dataåtkomstmönster som ska användas, samt anpassa namnen på de metoder som genereras. För fyllningsmönstret ska vi ändra namnet till FillByCategoryID och för returen ett DataTable-returmönster ( GetX metoderna) ska vi använda GetProductsByCategoryID.

Välj namn för TableAdapter-metoderna

Bild 17: Välj namnen för TableAdapter-metoderna (Klicka om du vill visa en bild i full storlek)

När du har slutfört guiden innehåller DataSet Designer de nya TableAdapter-metoderna.

Produkterna kan nu frågas efter kategori

Bild 18: Produkterna kan nu efterfrågas efter kategori

Ta en stund att lägga till en GetProductByProductID(productID) metod med samma teknik.

Dessa parametriserade frågor kan testas direkt från DataSet Designer. Högerklicka på metoden i TableAdapter och välj Förhandsgranska data. Ange sedan de värden som ska användas för parametrarna och klicka på Förhandsgranska.

De produkter som hör till kategorin Drycker visas

Bild 19: De produkter som hör till kategorin Drycker visas (Klicka om du vill visa en bild i full storlek)

GetProductsByCategoryID(categoryID) Med metoden i vår DAL kan vi nu skapa en ASP.NET sida som endast visar dessa produkter i en angiven kategori. I följande exempel visas alla produkter som finns i kategorin Drycker, som har värdet CategoryID 1.

Beverages.aspx

<%@ Page Language="VB" AutoEventWireup="true" CodeFile="Beverages.aspx.vb"
    Inherits="Beverages" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>Beverages</h1>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             CssClass="DataWebControlStyle">
               <HeaderStyle CssClass="HeaderStyle" />
               <AlternatingRowStyle CssClass="AlternatingRowStyle" />
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

Beverages.aspx.vb

Imports NorthwindTableAdapters
Partial Class Beverages
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles Me.Load
        Dim productsAdapter As New ProductsTableAdapter
        GridView1.DataSource =
         productsAdapter.GetProductsByCategoryID(1)
        GridView1.DataBind()
    End Sub
End Class

Dessa produkter i kategorin Drycker visas

Bild 20: Dessa produkter i kategorin Drycker visas (Klicka om du vill visa en bild i full storlek)

Steg 4: Infoga, uppdatera och ta bort data

Det finns två mönster som ofta används för att infoga, uppdatera och ta bort data. Det första mönstret, som jag kallar databasens direktmönster, handlar om att skapa metoder som, när det anropas, utfärdar ett INSERT, UPDATEeller DELETE -kommando till databasen som fungerar på en enda databaspost. Sådana metoder skickas vanligtvis i en serie skalära värden (heltal, strängar, booleska värden, DateTimes och så vidare) som motsvarar värdena för att infoga, uppdatera eller ta bort. Med det här mönstret för Products tabellen skulle borttagningsmetoden till exempel ta in en heltalsparameter som anger ProductID posten som ska tas bort, medan insert-metoden skulle ta in en sträng för ProductName, en decimal för UnitPrice, ett heltal för UnitsOnStockoch så vidare.

Varje infognings-, uppdaterings- och borttagningsbegäran skickas till databasen omedelbart

Bild 21: Varje infognings-, uppdaterings- och borttagningsbegäran skickas till databasen omedelbart (klicka om du vill visa en bild i full storlek)

Det andra mönstret, som jag kallar batchuppdateringsmönstret, är att uppdatera en hel DataSet, DataTable eller insamling av DataRows i ett metodanrop. Med det här mönstret tar en utvecklare bort, lägger till och ändrar DataRows i en DataTable och skickar sedan dessa DataRows eller DataTable till en uppdateringsmetod. Den här metoden räknar sedan upp datarows som skickas in, avgör om de har ändrats, lagts till eller tagits bort (via DataRows RowState-egenskapsvärde ) och utfärdar lämplig databasbegäran för varje post.

Alla ändringar synkroniseras med databasen när uppdateringsmetoden anropas

Bild 22: Alla ändringar synkroniseras med databasen när uppdateringsmetoden anropas (Klicka om du vill visa en bild i full storlek)

TableAdapter använder batchuppdateringsmönstret som standard, men stöder även db-direktmönstret. Eftersom vi valde alternativet "Generera infognings-, uppdaterings- och borttagningsuttryck" från avancerade egenskaper när vi skapade vår TableAdapter, ProductsTableAdapter innehåller metoden en Update() metod som implementerar batchuppdateringsmönstret. Mer specifikt innehåller TableAdapter en Update() metod som kan skickas till Typed DataSet, en starkt typad DataTable eller en eller flera DataRows. Om du lämnade kryssrutan "GenerateDBDirectMethods" markerad när du först skapade TableAdapter implementeras db-direktmönstret också via Insert(), Update()och Delete() -metoder.

Båda datamodifieringsmönstren använder TableAdapter-egenskaperna InsertCommand, UpdateCommandoch DeleteCommand för att utfärda kommandona INSERT, UPDATEoch DELETE till databasen. Du kan inspektera och ändra InsertCommandegenskaperna , UpdateCommandoch DeleteCommand genom att klicka på TableAdapter i DataSet Designer och sedan gå till fönstret Egenskaper. (Kontrollera att du har valt TableAdapter och att objektet är det objekt som ProductsTableAdapter har valts i listrutan i fönstret Egenskaper.)

TableAdapter har egenskaper för InsertCommand, UpdateCommand och DeleteCommand

Bild 23: TableAdapter har InsertCommand, UpdateCommandoch DeleteCommand egenskaper (Klicka om du vill visa en bild i full storlek)

Om du vill undersöka eller ändra någon av dessa egenskaper för databaskommandon klickar du på CommandText underegenskaperna, som tar upp Query Builder.

Konfigurera INSERT-, UPDATE- och DELETE-uttrycken i Query Builder

Bild 24: Konfigurera instruktionen INSERT, UPDATEoch DELETE i Query Builder (Klicka om du vill visa en bild i full storlek)

Följande kodexempel visar hur du använder batchuppdateringsmönstret för att fördubbla priset för alla produkter som inte har upphört och som har 25 enheter i lager eller mindre:

Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
Dim products As Northwind.ProductsDataTable = productsAdapter.GetProducts()
For Each product As Northwind.ProductsRow In products
   If Not product.Discontinued AndAlso product.UnitsInStock <= 25 Then
      product.UnitPrice *= 2
   End if
Next
productsAdapter.Update(products)

Koden nedan visar hur du använder db-direktmönstret för att programmatiskt ta bort en viss produkt, sedan uppdatera en och sedan lägga till en ny:

Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
productsAdapter.Delete(3)
productsAdapter.Update( _
    "Chai", 1, 1, "10 boxes x 20 bags", 18.0, 39, 15, 10, false, 1)
productsAdapter.Insert( _
    "New Product", 1, 1, "12 tins per carton", 14.95, 15, 0, 10, false)

Skapa anpassade metoder för att infoga, uppdatera och ta bort

Metoderna Insert(), Update()och som Delete() skapas av DB-direktmetoden kan vara lite besvärliga, särskilt för tabeller med många kolumner. Om du tittar på det tidigare kodexemplet, utan IntelliSenses hjälp, är det inte särskilt tydligt vilken tabellkolumn som Products mappar till varje indataparameter till Update() metoderna och Insert() . Det kan finnas tillfällen då vi bara vill uppdatera en enskild kolumn eller två eller vill ha en anpassad Insert() metod som kanske returnerar värdet för den nyligen infogade postens IDENTITY fält (automatisk inkrement).

Om du vill skapa en sådan anpassad metod går du tillbaka till DataSet Designer. Högerklicka på TableAdapter och välj Lägg till fråga och gå tillbaka till guiden TableAdapter. På den andra skärmen kan vi ange vilken typ av fråga som ska skapas. Nu ska vi skapa en metod som lägger till en ny produkt och sedan returnerar värdet för den nyligen tillagda postens ProductID. Välj därför att skapa en INSERT fråga.

Skapa en metod för att lägga till en ny rad i produkttabellen

Bild 25: Skapa en metod för att lägga till en ny rad i Products tabellen (Klicka om du vill visa en bild i full storlek)

På nästa skärm visas InsertCommands CommandText. Utöka den här frågan genom att lägga till SELECT SCOPE_IDENTITY() i slutet av frågan, vilket returnerar det sista identitetsvärdet som infogats i en IDENTITY kolumn i samma omfång. (Se den tekniska dokumentationen för mer information om SCOPE_IDENTITY() och varför du förmodligen vill använda SCOPE_IDENTITY() i stället för @@IDENTITY.) Se till att du avslutar -instruktionen INSERT med ett semikolon innan du lägger till -instruktionen SELECT .

Utöka frågan för att returnera värdet SCOPE_IDENTITY()

Bild 26: Utöka frågan för att returnera SCOPE_IDENTITY() värdet (Klicka om du vill visa en bild i full storlek)

Namnge slutligen den nya metoden InsertProduct.

Ange det nya metodnamnet till InsertProduct

Bild 27: Ange nytt metodnamn till InsertProduct (Klicka om du vill visa en bild i full storlek)

När du återvänder till DataSet Designer ser du att ProductsTableAdapter innehåller en ny metod, InsertProduct. Om den här nya metoden inte har någon parameter för varje kolumn i Products tabellen är chansen stor att du har glömt att avsluta -instruktionen INSERT med ett semikolon. InsertProduct Konfigurera metoden och se till att du har ett semikolon som avgränsar - och-uttrycken INSERTSELECT.

Som standard utfärdar infogningsmetoder icke-frågemetoder, vilket innebär att de returnerar antalet berörda rader. Vi vill InsertProduct dock att metoden ska returnera det värde som returneras av frågan, inte antalet rader som påverkas. För att åstadkomma detta, justera metodens InsertProduct egenskap till ExecuteMode.

Ändra egenskapen ExecuteMode till Scalar

Bild 28: Ändra egenskapen ExecuteMode till Scalar (Klicka om du vill visa en bild i full storlek)

Följande kod visar den här nya InsertProduct metoden i praktiken:

Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
Dim new_productID As Integer = Convert.ToInt32(productsAdapter.InsertProduct( _
    "New Product", 1, 1, "12 tins per carton", 14.95, 10, 0, 10, false))
productsAdapter.Delete(new_productID)

Steg 5: Slutföra dataåtkomstlagret

Observera att ProductsTableAdapters klassen returnerar CategoryID värdena och SupplierID från Products tabellen, men inte innehåller CategoryName kolumnen från Categories tabellen eller CompanyName kolumnen från Suppliers tabellen, även om dessa troligen är de kolumner som vi vill visa när produktinformationen visas. Vi kan utöka TableAdapters initiala metod GetProducts() så att både CategoryName- och CompanyName-kolumnvärdena inkluderas, vilket uppdaterar den starkt typade DataTable så att även dessa nya kolumner inkluderas.

Detta kan dock innebära ett problem eftersom TableAdapter-metoderna för att infoga, uppdatera och ta bort data baseras på den här initiala metoden. Lyckligtvis påverkas inte de automatiskt genererade metoderna för infogning, uppdatering och borttagning av underfrågor i SELECT -satsen. Genom att lägga till våra frågor i Categories och Suppliers som underfrågor, i stället JOIN för s, undviker vi att behöva omarbeta dessa metoder för att ändra data. Högerklicka på GetProducts() metoden i ProductsTableAdapter och välj Konfigurera. Justera SELECT sedan satsen så att den ser ut så här:

SELECT     ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
(SELECT CategoryName FROM Categories
WHERE Categories.CategoryID = Products.CategoryID) as CategoryName,
(SELECT CompanyName FROM Suppliers
WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName
FROM         Products

Uppdatera SELECT-instruktionen för metoden GetProducts()

Bild 29: Uppdatera instruktionen SELECTGetProducts() för metoden (Klicka om du vill visa en bild i full storlek)

När du har uppdaterat GetProducts() metoden för att använda den här nya frågan innehåller DataTable två nya kolumner: CategoryName och SupplierName.

Produktdatatabellen har två nya kolumner

Bild 30: Products DataTable har två nya kolumner

Ta en stund att uppdatera SELECT satsen i GetProductsByCategoryID(categoryID) -metoden också.

Om du använder syntaxen GetProducts() för att uppdatera SELECTJOIN kommer inte DataSet Designer att kunna generera metoderna för att infoga, uppdatera och ta bort databasdata automatiskt med hjälp av DB-direktmönstret. I stället måste du skapa dem manuellt på samma sätt som vi gjorde med InsertProduct-metoden tidigare i den här självstudien. Dessutom måste du manuellt ange egenskapsvärdena InsertCommand, UpdateCommandoch DeleteCommand om du vill använda batchuppdateringsmönstret.

Lägga till återstående TableAdapters

Hittills har vi bara tittat på att arbeta med en enda TableAdapter för en enskild databastabell. Northwind-databasen innehåller dock flera relaterade tabeller som vi behöver arbeta med i vårt webbprogram. En Typed DataSet kan innehålla flera relaterade DataTables. För att slutföra vår DAL behöver vi därför lägga till DataTables för de andra tabellerna som vi kommer att använda i de här självstudierna. Om du vill lägga till en ny TableAdapter i en Typed DataSet öppnar du DataSet Designer, högerklickar i Designer och väljer Lägg till/TableAdapter. Detta skapar en ny DataTable och TableAdapter och vägleder dig genom guiden som vi granskade tidigare i den här handledningen.

Det tar några minuter att skapa följande TableAdapters och metoder med hjälp av följande frågor. Observera att frågorna i ProductsTableAdapter inkluderar underfrågorna för att hämta varje produkts kategori- och leverantörsnamn. Om du har följt med har du dessutom redan lagt till ProductsTableAdapter klassens GetProducts() och GetProductsByCategoryID(categoryID) metoderna.

  • ProductsTableAdapter

    • GetProducts:

      SELECT     ProductID, ProductName, SupplierID, 
      CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, 
      UnitsOnOrder, ReorderLevel, Discontinued, 
      (SELECT CategoryName FROM Categories WHERE
      Categories.CategoryID = Products.CategoryID) as 
      CategoryName, (SELECT CompanyName FROM Suppliers
      WHERE Suppliers.SupplierID = Products.SupplierID) 
      as SupplierName
      FROM         Products
      
    • GetProductsByCategoryID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName,
      (SELECT CompanyName FROM Suppliers WHERE
      Suppliers.SupplierID = Products.SupplierID)
      as SupplierName
      FROM         Products
      WHERE      CategoryID = @CategoryID
      
    • GetProductsBySupplierID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName, 
      (SELECT CompanyName FROM Suppliers WHERE 
      Suppliers.SupplierID = Products.SupplierID) as SupplierName
      FROM         Products
      WHERE SupplierID = @SupplierID
      
    • GetProductByProductID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName 
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName, 
      (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) 
      as SupplierName
      FROM         Products
      WHERE ProductID = @ProductID
      
  • KategorierTabelladapter

    • GetCategories:

      SELECT     CategoryID, CategoryName, Description
      FROM         Categories
      
    • GetCategoryByCategoryID:

      SELECT     CategoryID, CategoryName, Description
      FROM         Categories
      WHERE CategoryID = @CategoryID
      
  • Leverantörstabelladaptör

    • GetSuppliers:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      
    • GetSuppliersByCountry:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      WHERE Country = @Country
      
    • GetSupplierBySupplierID:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      WHERE SupplierID = @SupplierID
      
  • EmployeesTableAdapter (på engelska)

    • GetEmployees:

      SELECT     EmployeeID, LastName, FirstName, Title,
      HireDate, ReportsTo, Country
      FROM         Employees
      
    • GetEmployeesByManager:

      SELECT     EmployeeID, LastName, FirstName, Title, 
      HireDate, ReportsTo, Country
      FROM         Employees
      WHERE ReportsTo = @ManagerID
      
    • GetEmployeeByEmployeeID:

      SELECT     EmployeeID, LastName, FirstName, Title,
      HireDate, ReportsTo, Country
      FROM         Employees
      WHERE EmployeeID = @EmployeeID
      

DataSet-designern efter att de fyra TableAdapters har lagts till

Bild 31: Datauppsättningsdesignern efter att de fyra TableAdapters har lagts till (klicka om du vill visa en bild i full storlek)

Lägga till anpassad kod i DAL

TableAdapters och DataTables som lagts till i Typed DataSet uttrycks som en XML-schemadefinitionsfil (Northwind.xsd). Du kan visa den här schemainformationen Northwind.xsd genom att högerklicka på filen i Solution Explorer och välja Visa kod.

XML-schemadefinitionsfilen (XSD) för Northwinds-typdatauppsättningen

Bild 32: XML-schemadefinitionsfilen (XSD) för DataSeten Northwinds-typ (klicka om du vill visa en bild i full storlek)

Den här schemainformationen översätts till C# eller Visual Basic-kod vid designtillfället när den kompileras eller vid körning (om det behövs), då du kan gå igenom den med felsökningsprogrammet. Om du vill visa den här automatiskt genererade koden går du till klassvyn och ökar detaljnivån till klasserna TableAdapter eller Typed DataSet. Om du inte ser klassvyn på skärmen går du till menyn Visa och väljer den därifrån eller trycker på Ctrl+Skift+C. I klassvyn kan du se egenskaperna, metoderna och händelserna för klasserna Typed DataSet och TableAdapter. Om du vill visa koden för en viss metod dubbelklickar du på metodnamnet i klassvyn eller högerklickar på den och väljer Gå till definition.

Granska den automatiskt genererade koden genom att välja Gå till definition från klassvyn

Bild 33: Inspektera den automatiskt genererade koden genom att välja Gå till definition från klassvyn

Även om automatisk genererad kod kan vara en bra tidssparare är koden ofta mycket allmän och måste anpassas för att uppfylla de unika behoven i ett program. Risken med att utöka automatiskt genererad kod är dock att verktyget som genererade koden kan avgöra att det är dags att "återskapa" och skriva över dina anpassningar. Med .NET 2.0:s nya partiella klasskoncept är det enkelt att dela upp en klass i flera filer. På så sätt kan vi lägga till egna metoder, egenskaper och händelser i de automatiskt genererade klasserna utan att behöva oroa oss för att Visual Studio ska skriva över våra anpassningar.

Vi visar hur du anpassar DAL genom att lägga till en GetProducts() metod i SuppliersRow klassen. Klassen SuppliersRow representerar en enda post i Suppliers tabellen. Varje leverantör kan tillhandahålla noll till många produkter, så GetProducts() returnerar de produkterna från den angivna leverantören. För att åstadkomma detta skapar du en ny klassfil i App_Code mappen med namnet SuppliersRow.vb och lägger till följande kod:

Imports NorthwindTableAdapters
Partial Public Class Northwind
    Partial Public Class SuppliersRow
        Public Function GetProducts() As Northwind.ProductsDataTable
            Dim productsAdapter As New ProductsTableAdapter
            Return productsAdapter.GetProductsBySupplierID(Me.SupplierID)
        End Function
    End Class
End Class

Den här partiella klassen instruerar kompilatorn att när du skapar Northwind.SuppliersRow klassen så att den innehåller den GetProducts() metod som vi precis har definierat. Om du skapar projektet och sedan återgår till klassvyn visas GetProducts() nu som en metod för Northwind.SuppliersRow.

Metoden GetProducts() är nu en del av Northwind.SuppliersRow-klassen

Bild 34: Metoden GetProducts() är nu en del av Northwind.SuppliersRow klassen

Metoden GetProducts() kan nu användas för att räkna upp produktuppsättningen för en viss leverantör, som följande kod visar:

Dim suppliersAdapter As New NorthwindTableAdapters.SuppliersTableAdapter()
Dim suppliers As Northwind.SuppliersDataTable = suppliersAdapter.GetSuppliers()
For Each supplier As Northwind.SuppliersRow In suppliers
    Response.Write("Supplier: " & supplier.CompanyName)
    Response.Write("<ul>")
    Dim products As Northwind.ProductsDataTable = supplier.GetProducts()
    For Each product As Northwind.ProductsRow In products
        Response.Write("<li>" & product.ProductName & "</li>")
    Next
    Response.Write("</ul><p> </p>")
Next

Denna data kan också visas i någon av ASP.NET:s datawebbkontroller. På följande sida används en GridView-kontroll med två fält:

  • Ett BoundField som visar namnet på varje leverantör och
  • Ett TemplateField som innehåller en bulletedList-kontroll som är bunden till de resultat som returneras av GetProducts() metoden för varje leverantör.

Vi kommer att undersöka hur man visar sådana master-detaljrapporter i framtida självstudier. För tillfället är det här exemplet utformat för att illustrera med hjälp av den anpassade metod som lagts till i Northwind.SuppliersRow klassen.

LeverantörerOchProdukter.aspx

<%@ Page Language="VB" CodeFile="SuppliersAndProducts.aspx.vb"
    AutoEventWireup="true" Inherits="SuppliersAndProducts" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>
            Suppliers and Their Products</h1>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             AutoGenerateColumns="False"
             CssClass="DataWebControlStyle">
                <HeaderStyle CssClass="HeaderStyle" />
                <AlternatingRowStyle CssClass="AlternatingRowStyle" />
                <Columns>
                    <asp:BoundField DataField="CompanyName"
                      HeaderText="Supplier" />
                    <asp:TemplateField HeaderText="Products">
                        <ItemTemplate>
                            <asp:BulletedList ID="BulletedList1"
                             runat="server" DataSource="<%# CType(CType(Container.DataItem, System.Data.DataRowView).Row, Northwind.SuppliersRow).GetProducts() %>"
                                 DataTextField="ProductName">
                            </asp:BulletedList>
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

SuppliersAndProducts.aspx.vb

Imports NorthwindTableAdapters
Partial Class SuppliersAndProducts
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles Me.Load
        Dim suppliersAdapter As New SuppliersTableAdapter
        GridView1.DataSource = suppliersAdapter.GetSuppliers()
        GridView1.DataBind()
    End Sub
End Class

Leverantörens företagsnamn visas i den vänstra kolumnen, deras produkter till höger

Bild 35: Leverantörens företagsnamn visas i den vänstra kolumnen, deras produkter till höger (klicka om du vill visa en bild i full storlek)

Sammanfattning

När du bygger en webbapplikation bör skapandet av DAL vara ett av dina första steg, innan du börjar skapa presentationslagret. Med Visual Studio är det en uppgift som kan utföras på 10–15 minuter att skapa en DAL baserat på typbaserade datauppsättningar utan att behöva skriva en kodrad. Handledningarna i fortsättningen bygger på denna DAL. I nästa handledning ska vi definiera ett antal affärsregler och se hur vi implementerar dem i ett separat affärslogikskikt.

Lycka till med programmerandet!

Ytterligare läsning

Mer information om de ämnen som beskrivs i den här självstudien finns i följande resurser:

Videoutbildning om ämnen som finns i den här handledningen

Om författaren

Scott Mitchell, författare till sju ASP/ASP.NET-böcker och grundare av 4GuysFromRolla.com, har arbetat med Microsofts webbtekniker sedan 1998. Scott arbetar som oberoende konsult, tränare och författare. Hans senaste bok är Sams Teach Yourself ASP.NET 2.0 på 24 timmar. Han kan nås på mitchell@4GuysFromRolla.com.

Särskilt tack till

Den här självstudieserien granskades av många användbara granskare. Huvudgranskare för den här självstudien var Ron Green, Hilton Giesenow, Dennis Patterson, Liz Shulok, Abel Gomez och Carlos Santos. Vill du granska mina kommande MSDN-artiklar? Om så är fallet, hör av dig på mitchell@4GuysFromRolla.com.