Tworzenie niestandardowego dostawcy map witryn opartych na bazie danych (C#)

Autor : Scott Mitchell

Pobierz plik PDF

Domyślny dostawca mapy witryny w ASP.NET 2.0 pobiera dane ze statycznego pliku XML. Dostawca oparty na formacie XML jest odpowiedni dla wielu małych i średnich witryn sieci Web, ale większe aplikacje sieci Web wymagają bardziej dynamicznej mapy witryny. W tym samouczku utworzymy niestandardowego dostawcę mapy lokacji, który pobiera dane z warstwy logiki biznesowej, który z kolei pobiera dane z bazy danych.

Wprowadzenie

funkcja mapy witryny w wersji ASP.NET 2.0 umożliwia deweloperowi strony zdefiniowanie mapy witryny aplikacji internetowej na nośniku trwałym, na przykład w pliku XML. Po zdefiniowaniu dane mapy witryny można uzyskać dostęp programowo za pośrednictwem klasy w System.Web przestrzeni nazw lub za pomocą SiteMap różnych kontrolek nawigacji w Sieci Web, takich jak SiteMapPath, Menu i TreeView. System mapy lokacji używa modelu dostawcy, aby można było utworzyć i podłączyć do aplikacji internetowej różne implementacje serializacji mapy witryny. Domyślny dostawca mapy witryny dostarczany z programem ASP.NET 2.0 utrwala strukturę mapy witryny w pliku XML. W samouczku dotyczącym stron wzorcowych i nawigacji po witrynie utworzyliśmy plik o nazwie Web.sitemap zawierający tę strukturę i zaktualizowaliśmy kod XML przy użyciu każdej nowej sekcji samouczka.

Domyślny dostawca mapy witryny oparty na formacie XML sprawdza się, jeśli struktura mapy witryny jest dość statyczna, na przykład w przypadku tych samouczków. Jednak w wielu scenariuszach potrzebna jest bardziej dynamiczna mapa lokacji. Rozważ mapę witryny pokazaną na rysunku 1, w której każda kategoria i produkt są wyświetlane jako sekcje w strukturze witryny internetowej. Na tej mapie witryny odwiedzanie strony internetowej odpowiadającej węzłowi głównemu może zawierać listę wszystkich kategorii, podczas gdy odwiedzanie określonej strony sieci Web kategorii spowoduje wyświetlenie tej kategorii produktów i wyświetlenie określonej strony sieci Web produktu spowoduje wyświetlenie tych szczegółów produktu.

Kategorie i produkty makijaż struktury mapy witryny

Rysunek 1. Kategorie i produkty makijaż struktury mapy witryny (kliknij, aby wyświetlić obraz pełnowymiarowy)

Chociaż ta struktura oparta na kategorii i produktach może być trwale zakodowana w Web.sitemap pliku, plik musi zostać zaktualizowany za każdym razem, gdy kategoria lub produkt został dodany, usunięty lub zmieniono jego nazwę. W związku z tym konserwacja mapy witryny byłaby znacznie uproszczona, jeśli jej struktura została pobrana z bazy danych lub, w idealnym przypadku, z warstwy logiki biznesowej architektury aplikacji. Dzięki temu w miarę dodawania produktów i kategorii, zmieniania ich nazwy lub usuwania mapa witryny zostanie automatycznie zaktualizowana, aby odzwierciedlić te zmiany.

Ponieważ ASP.NET serializacji mapy lokacji w wersji 2.0 jest tworzona na szczycie modelu dostawcy, możemy utworzyć własnego niestandardowego dostawcę mapy witryny, który pobiera dane z alternatywnego magazynu danych, takiego jak baza danych lub architektura. W tym samouczku utworzymy dostawcę niestandardowego, który pobiera dane z usługi BLL. Zacznijmy!

Uwaga

Niestandardowy dostawca mapy witryny utworzony w tym samouczku jest ściśle powiązany z architekturą aplikacji i modelem danych. Jeff Prosise storing Site Maps in SQL Server and The SQL Site Map Provider You been Waiting For articles examine a generalized approach to storing site map data in SQL Server .The SQL Site Map Provider You BeenAiting For articles examine a generalized approach to storing site map data in SQL Server (Przechowywanie map witryn w SQL Server).

Krok 1. Tworzenie niestandardowych stron sieci Web dostawcy map witryn

Przed rozpoczęciem tworzenia niestandardowego dostawcy mapy witryny najpierw dodajmy strony ASP.NET, które będą potrzebne w tym samouczku. Zacznij od dodania nowego folderu o nazwie SiteMapProvider. Następnie dodaj do tego folderu następujące strony ASP.NET, aby skojarzyć każdą stronę ze stroną wzorcową Site.master :

  • Default.aspx
  • ProductsByCategory.aspx
  • ProductDetails.aspx

CustomProviders Dodaj również podfolder do App_Code folderu .

Dodawanie stron ASP.NET dla samouczków mapy witryny Provider-Related

Rysunek 2. Dodawanie stron ASP.NET dla mapy witryny Provider-Related Samouczki

Ponieważ w tej sekcji jest tylko jeden samouczek, nie musimy Default.aspx wyświetlać listy samouczków sekcji. Default.aspx Zamiast tego zostaną wyświetlone kategorie w kontrolce GridView. Zajmiemy się tym w kroku 2.

Następnie zaktualizuj Web.sitemap element , aby uwzględnić odwołanie do Default.aspx strony. W szczególności dodaj następujące znaczniki po buforowaniu <siteMapNode>:

<siteMapNode 
    title="Customizing the Site Map" url="~/SiteMapProvider/Default.aspx" 
    description="Learn how to create a custom provider that retrieves the site map 
                 from the Northwind database." />

Po zaktualizowaniu Web.sitemapprogramu poświęć chwilę, aby wyświetlić witrynę internetową samouczków za pośrednictwem przeglądarki. Menu po lewej stronie zawiera teraz element dla jedynego samouczka dostawcy mapy witryny.

Mapa witryny zawiera teraz wpis dla samouczka dostawcy mapy witryny

Rysunek 3. Mapa witryny zawiera teraz wpis dla samouczka dostawcy mapy witryny

Głównym celem tego samouczka jest zilustrowanie tworzenia niestandardowego dostawcy mapy witryny i konfigurowania aplikacji internetowej do korzystania z tego dostawcy. W szczególności utworzymy dostawcę, który zwraca mapę witryny zawierającą węzeł główny wraz z węzłem dla każdej kategorii i produktu, jak pokazano na rysunku 1. Ogólnie rzecz biorąc, każdy węzeł na mapie witryny może określać adres URL. W przypadku mapy naszej witryny adres URL węzła głównego będzie ~/SiteMapProvider/Default.aspxmieć wartość , która będzie zawierać listę wszystkich kategorii w bazie danych. Każdy węzeł kategorii na mapie witryny będzie miał adres URL wskazujący element , który będzie zawierać ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryIDlistę wszystkich produktów w określonej kategoriiID. Na koniec każdy węzeł mapy witryny produktu wskaże ~/SiteMapProvider/ProductDetails.aspx?ProductID=productIDelement , który wyświetli szczegóły określonego produktu.

Aby rozpocząć, musimy utworzyć Default.aspxstrony , ProductsByCategory.aspxi ProductDetails.aspx . Te strony są wykonywane odpowiednio w krokach 2, 3 i 4. Ponieważ ten samouczek jest oparty na dostawcach mapy witryny, a od poprzednich samouczków omówiliśmy tworzenie tego rodzaju wielostronicowych raportów wzorcowych/szczegółowych, pospieszniemy się przez kroki od 2 do 4. Jeśli potrzebujesz odświeżenia podczas tworzenia raportów wzorca/szczegółów obejmujących wiele stron, zapoznaj się z samouczkiem Filtrowanie wzorca/szczegółów na dwóch stronach .

Krok 2. Wyświetlanie listy kategorii

Default.aspx Otwórz stronę w folderze SiteMapProvider i przeciągnij kontrolkę GridView z przybornika do Projektant, ustawiając jej ID wartość na Categories. Z tagu inteligentnego GridView powiąż go z nową wartością ObjectDataSource o nazwie CategoriesDataSource i skonfiguruj ją tak, aby pobierała dane przy użyciu CategoriesBLL metody klasy s GetCategories . Ponieważ ten obiekt GridView wyświetla tylko kategorie i nie udostępnia możliwości modyfikacji danych, ustaw listy rozwijane na kartach UPDATE, INSERT i DELETE na wartość (Brak).

Konfigurowanie obiektu ObjectDataSource do zwracania kategorii przy użyciu metody GetCategories

Rysunek 4. Konfigurowanie obiektu ObjectDataSource do zwracania kategorii przy użyciu GetCategories metody (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Ustaw Drop-Down Listy na kartach UPDATE, INSERT i DELETE na wartość (Brak)

Rysunek 5. Ustawianie Drop-Down Listy na kartach UPDATE, INSERT i DELETE na wartość (Brak) (kliknij, aby wyświetlić obraz w pełnym rozmiarze)

Po zakończeniu pracy kreatora Konfigurowanie źródła danych program Visual Studio doda pole BoundField dla CategoryID, , DescriptionCategoryName, NumberOfProductsi BrochurePath. Zmodyfikuj obiekt GridView, tak aby zawierał tylko pola CategoryName i i Description i zaktualizuj CategoryName właściwość BoundField HeaderText do właściwości Category .

Następnie dodaj pole HyperLinkField i umieść je tak, aby było to pole najbardziej po lewej stronie. DataNavigateUrlFields Ustaw właściwość na CategoryID , a DataNavigateUrlFormatString właściwość na ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}. Text Ustaw właściwość na Wyświetl produkty .

Dodawanie obiektu HyperLinkField do kontrolki GridView kategorii

Rysunek 6. Dodawanie obiektu HyperLinkField do kontrolki Categories GridView

Po utworzeniu obiektu ObjectDataSource i dostosowaniu pól kontrolki GridView znacznik deklaratywny będzie wyglądać następująco:

<asp:GridView ID="Categories" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="CategoryID" DataSourceID="CategoriesDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:HyperLinkField DataNavigateUrlFields="CategoryID" 
            DataNavigateUrlFormatString=
                "~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}"
            Text="View Products" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" 
            SortExpression="CategoryName" />
        <asp:BoundField DataField="Description" HeaderText="Description" 
            SortExpression="Description" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories" 
    TypeName="CategoriesBLL"></asp:ObjectDataSource>

Rysunek 7 przedstawia Default.aspx widok w przeglądarce. Kliknięcie linku Wyświetl produkty kategorii spowoduje przejście do ProductsByCategory.aspx?CategoryID=categoryIDelementu , który utworzymy w kroku 3.

Każda kategoria jest wyświetlana wraz z linkiem Wyświetl produkty

Rysunek 7. Każda kategoria jest wyświetlana wraz z linkiem Wyświetl produkty (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 3. Wyświetlanie listy wybranych produktów kategorii

ProductsByCategory.aspx Otwórz stronę i dodaj kontrolkę GridView, nazewając ją ProductsByCategory. Z tagu inteligentnego powiąż element GridView z nowym obiektem ObjectDataSource o nazwie ProductsByCategoryDataSource. Skonfiguruj obiekt ObjectDataSource do używania ProductsBLL metody s GetProductsByCategoryID(categoryID) klasy i ustaw listy rozwijane na wartość (Brak) na kartach UPDATE, INSERT i DELETE.

Użyj metody GetProductsByCategoryID(categoryID) klasy ProductsBLL

Rysunek 8. Użycie ProductsBLL metody klasy GetProductsByCategoryID(categoryID) (kliknij, aby wyświetlić obraz pełnowymiarowy)

Ostatni krok kreatora Konfigurowanie źródła danych wyświetla monit o podanie źródła parametrów dla categoryID. Ponieważ te informacje są przekazywane przez pole CategoryIDquerystring, wybierz pozycję QueryString z listy rozwijanej i wprowadź ciąg CategoryID w polu tekstowym QueryStringField, jak pokazano na rysunku 9. Kliknij przycisk Zakończ, aby zakończyć kreatora.

Użyj pola Querystring CategoryID dla parametru categoryID

Rysunek 9. Użyj pola querystring dla parametru CategoryIDcategoryID (kliknij, aby wyświetlić obraz pełnowymiarowy)

Po ukończeniu pracy kreatora program Visual Studio doda odpowiednie pola BoundFields i CheckBoxField do kontrolki GridView dla pól danych produktu. Usuń wszystkie elementy ProductNameoprócz pól , UnitPricei SupplierName BoundFields. Dostosuj te trzy właściwości BoundFields HeaderText , aby odpowiednio odczytywać pozycje Product (Produkt), Price (Cena) i Supplier (Dostawca). Sformatuj pole UnitPrice Powiązane jako walutę.

Następnie dodaj wartość HyperLinkField i przenieś ją do lewej pozycji. Ustaw jej Text właściwość na View Details, jej DataNavigateUrlFields właściwość na ProductID, a jej DataNavigateUrlFormatString właściwość na ~/SiteMapProvider/ProductDetails.aspx?ProductID={0}.

Dodawanie pola HyperLinkField szczegółów widoku wskazującego ProductDetails.aspx

Rysunek 10. Dodawanie pola hiperlinkowego widoku wskazującego ProductDetails.aspx

Po wprowadzeniu tych dostosowań znaczniki deklaratywne gridView i ObjectDataSource powinny wyglądać podobnie do następujących:

<asp:GridView ID="ProductsByCategory" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ProductsByCategoryDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:HyperLinkField DataNavigateUrlFields="ProductID" 
            DataNavigateUrlFormatString=
                "~/SiteMapProvider/ProductDetails.aspx?ProductID={0}"
            Text="View Details" />
        <asp:BoundField DataField="ProductName" HeaderText="Product"
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" 
            HeaderText="Price" HtmlEncode="False" 
            SortExpression="UnitPrice" />
        <asp:BoundField DataField="SupplierName" HeaderText="Supplier" 
            ReadOnly="True" SortExpression="SupplierName" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsByCategoryDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
    <SelectParameters>
        <asp:QueryStringParameter Name="categoryID" 
            QueryStringField="CategoryID" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

Wróć do przeglądania Default.aspx za pośrednictwem przeglądarki i kliknij link Wyświetl produkty dla napojów. Spowoduje ProductsByCategory.aspx?CategoryID=1to wyświetlenie nazw, cen i dostawców produktów w bazie danych Northwind należących do kategorii Napoje (patrz Rysunek 11). Możesz dodatkowo ulepszyć tę stronę, aby dołączyć link umożliwiający zwrócenie użytkowników do strony listy kategorii (Default.aspx) oraz kontrolki DetailsView lub FormView, która wyświetla nazwę i opis wybranej kategorii.

Nazwy napojów, ceny i dostawcy są wyświetlane

Rysunek 11. Wyświetlane są nazwy napojów, ceny i dostawcy (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 4. Wyświetlanie szczegółów produktu

Ostatnia strona , ProductDetails.aspxwyświetla szczegóły wybranych produktów. Otwórz ProductDetails.aspx i przeciągnij element DetailsView z przybornika do Projektant. Ustaw właściwość Kontrolka ID DetailsView na ProductInfo i wyczyść jej Height wartości właściwości i Width . Z tagu inteligentnego powiąż element DetailsView z nową klasą ObjectDataSource o nazwie ProductDataSource, konfigurując element ObjectDataSource w celu ściągnięcia danych z ProductsBLL metody klasy s GetProductByProductID(productID) . Podobnie jak w przypadku poprzednich stron sieci Web utworzonych w krokach 2 i 3, ustaw listy rozwijane na kartach UPDATE, INSERT i DELETE na wartość (Brak).

Konfigurowanie obiektu ObjectDataSource do używania metody GetProductByProductID(productID)

Rysunek 12. Konfigurowanie obiektu ObjectDataSource do użycia GetProductByProductID(productID) metody (kliknij, aby wyświetlić obraz w pełnym rozmiarze)

W ostatnim kroku Kreatora konfigurowania źródła danych zostanie wyświetlony monit o podanie źródła parametru productID . Ponieważ te dane są przekazywane przez pole ProductIDquerystring, ustaw listę rozwijaną na QueryString i pole tekstowe QueryStringField na ProductID. Na koniec kliknij przycisk Zakończ, aby zakończyć pracę kreatora.

Konfigurowanie parametru productID w celu ściągnięcia jego wartości z pola ProductID Querystring

Rysunek 13. Konfigurowanie parametru productID w celu ściągnięcia jego wartości z ProductID pola querystring (kliknij, aby wyświetlić obraz pełnowymiarowy)

Po zakończeniu pracy kreatora Konfigurowanie źródła danych program Visual Studio utworzy odpowiednie pola BoundFields i Pole CheckBoxField w obszarze DetailsView dla pól danych produktu. ProductIDUsuń pola , SupplierIDi CategoryID BoundFields i skonfiguruj pozostałe pola zgodnie z potrzebami. Po kilku konfiguracjach estetycznych znaczniki deklaratywne obiektów DetailsView i ObjectDataSource wyglądały następująco:

<asp:DetailsView ID="ProductInfo" runat="server" AutoGenerateRows="False" 
    DataKeyNames="ProductID" DataSourceID="ProductDataSource" 
    EnableViewState="False">
    <Fields>
        <asp:BoundField DataField="ProductName" HeaderText="Product" 
            SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" 
            ReadOnly="True" SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName" HeaderText="Supplier" 
            ReadOnly="True" SortExpression="SupplierName" />
        <asp:BoundField DataField="QuantityPerUnit" HeaderText="Qty/Unit" 
            SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" 
            HeaderText="Price" HtmlEncode="False" 
            SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock" HeaderText="Units In Stock" 
            SortExpression="UnitsInStock" />
        <asp:BoundField DataField="UnitsOnOrder" HeaderText="Units On Order" 
            SortExpression="UnitsOnOrder" />
        <asp:BoundField DataField="ReorderLevel" HeaderText="Reorder Level" 
            SortExpression="ReorderLevel" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" 
            SortExpression="Discontinued" />
    </Fields>
</asp:DetailsView>
<asp:ObjectDataSource ID="ProductDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProductByProductID" TypeName="ProductsBLL">
    <SelectParameters>
        <asp:QueryStringParameter Name="productID" 
            QueryStringField="ProductID" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

Aby przetestować tę stronę, wróć do Default.aspx i kliknij pozycję Wyświetl produkty dla kategorii Napoje. Na liście produktów napojów kliknij link Wyświetl szczegóły dla Chai Tea. Spowoduje to przejście do ProductDetails.aspx?ProductID=1obiektu , w którym zostaną wyświetlone szczegóły Chai Tea (patrz Rysunek 14).

Dostawca Chai Tea s, Kategoria, Cena i Inne informacje są wyświetlane

Rysunek 14. Chai Tea s Supplier, Category, Price i Other Information is Displayed (Kliknij, aby wyświetlić pełny obraz)

Krok 5. Opis wewnętrznych funkcji dostawcy mapy lokacji

Mapa witryny jest reprezentowana w pamięci serwera internetowego jako zbiór SiteMapNode wystąpień, które tworzą hierarchię. Musi istnieć dokładnie jeden katalog główny, wszystkie węzły inne niż główne muszą mieć dokładnie jeden węzeł nadrzędny, a wszystkie węzły mogą mieć dowolną liczbę elementów podrzędnych. Każdy SiteMapNode obiekt reprezentuje sekcję w strukturze witryny sieci Web. Te sekcje często mają odpowiednią stronę internetową. W związku z tym SiteMapNode klasa ma właściwości takie jak Title, Urli Description, które zawierają informacje dotyczące sekcji reprezentowanej przez klasę SiteMapNode . Istnieje również Key właściwość, która jednoznacznie identyfikuje każdą SiteMapNode z nich w hierarchii, a także właściwości używane do ustanowienia tej hierarchii ChildNodes, , ParentNodeNextSibling, PreviousSiblingi tak dalej.

Rysunek 15 przedstawia ogólną strukturę mapy witryny z rysunku 1, ale szczegóły implementacji zostały naszkicowane bardziej szczegółowymi szczegółami.

Każdy element SiteMapNode ma właściwości, takie jak tytuł, adres URL, klucz itd.

Rysunek 15. Każda z nich SiteMapNode ma właściwości takie jak Title, Url, Keyi tak dalej (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Mapa witryny jest dostępna za pośrednictwem SiteMap klasy w System.Web przestrzeni nazw. Ta właściwość klasy RootNode zwraca wystąpienie główne SiteMapNode mapy witryny. CurrentNode Zwraca SiteMapNode właściwość, której Url właściwość odpowiada adresowi URL aktualnie żądanej strony. Ta klasa jest używana wewnętrznie przez kontrolki sieci Web nawigacji ASP.NET 2.0.

SiteMap Po korzystaniu z właściwości klasy należy serializować strukturę mapy lokacji z pewnego nośnika trwałego do pamięci. Jednak logika serializacji mapy witryny nie jest zakodowana w SiteMap klasie. Zamiast tego w czasie wykonywania SiteMap klasa określa , który dostawca mapy lokacji ma być używany do serializacji. Domyślnie jest używana klasa,XmlSiteMapProvider która odczytuje strukturę mapy witryny z poprawnie sformatowanego pliku XML. Jednak przy odrobinie pracy możemy utworzyć własnego niestandardowego dostawcę mapy witryny.

Wszyscy dostawcy mapy witryny muszą pochodzić z SiteMapProvider klasy , która zawiera podstawowe metody i właściwości potrzebne dla dostawców mapy witryny, ale pomija wiele szczegółów implementacji. Druga klasa, StaticSiteMapProvider, rozszerza klasę SiteMapProvider i zawiera bardziej niezawodną implementację wymaganych funkcji. Wewnętrznie program StaticSiteMapProvider przechowuje SiteMapNode wystąpienia mapy witryny w obiekcie Hashtable i udostępnia metody, takie jak AddNode(child, parent), RemoveNode(siteMapNode), oraz Clear() , które dodają i usuwają SiteMapNode obiekty do wewnętrznego Hashtableobiektu . XmlSiteMapProviderpochodzi z .StaticSiteMapProvider

Podczas tworzenia niestandardowego dostawcy mapy witryny, który rozszerza StaticSiteMapProviderusługę , istnieją dwie metody abstrakcyjne, które muszą zostać zastąpione: BuildSiteMap i GetRootNodeCore. BuildSiteMap, jak wskazuje jej nazwa, jest odpowiedzialny za ładowanie struktury mapy lokacji z magazynu trwałego i konstruowanie jej w pamięci. GetRootNodeCore Zwraca węzeł główny na mapie witryny.

Aby aplikacja internetowa mogła korzystać z dostawcy mapy witryny, musi zostać zarejestrowana w konfiguracji aplikacji. Domyślnie klasa jest rejestrowana XmlSiteMapProvider przy użyciu nazwy AspNetXmlSiteMapProvider. Aby zarejestrować dodatkowych dostawców mapy witryny, dodaj następujące znaczniki do :Web.config

<configuration>
    <system.web>
        ...
        <siteMap defaultProvider="defaultProviderName">
          <providers>
            <add name="name" type="type" />
          </providers>
        </siteMap>
    </system.web>
</configuration>

Wartość nazwy przypisuje nazwę czytelną dla człowieka do dostawcy, podczas gdy typ określa w pełni kwalifikowaną nazwę typu dostawcy mapy witryny. Zapoznamy się z konkretnymi wartościami nazw i typów w kroku 7 po utworzeniu niestandardowego dostawcy mapy witryny.

Klasa dostawcy mapy witryny jest tworzone przy pierwszym uzyskiwaniu dostępu z SiteMap klasy i pozostaje w pamięci przez cały okres istnienia aplikacji internetowej. Ponieważ istnieje tylko jedno wystąpienie dostawcy mapy witryny, które może być wywoływane z wielu, współbieżnych odwiedzających witrynę sieci Web, konieczne jest, aby metody dostawcy były bezpieczne wątkowo.

Ze względu na wydajność i skalowalność ważne jest buforowanie struktury mapy lokacji w pamięci i zwracanie tej buforowanej struktury zamiast ponownego tworzenia jej za każdym razem, gdy BuildSiteMap metoda jest wywoływana. BuildSiteMap W zależności od kontrolek nawigacji używanych na stronie na stronie i głębokości struktury mapy witryny może być wywoływana kilka razy na żądanie strony. W każdym razie, jeśli nie będziemy buforować struktury mapy witryny za BuildSiteMap każdym razem, gdy jest wywoływany, musimy ponownie pobrać informacje o produkcie i kategorii z architektury (co spowodowałoby zapytanie do bazy danych). Jak omówiono w poprzednich samouczkach dotyczących buforowania, buforowane dane mogą stać się nieaktualne. Aby temu zastosować, możemy użyć czasu lub wygaśnięcia opartych na zależnościach pamięci podręcznej SQL.

Uwaga

Dostawca mapy witryny może opcjonalnie zastąpić metodęInitialize . Initialize jest wywoływany po pierwszym utworzeniu wystąpienia dostawcy mapy witryny i jest przekazywany wszystkie atrybuty niestandardowe przypisane do dostawcy w Web.config elemecie <add> , na przykład: <add name="name" type="type" customAttribute="value" />. Jest to przydatne, jeśli chcesz zezwolić deweloperowi strony na określanie różnych ustawień związanych z dostawcą mapy witryny bez konieczności modyfikowania kodu dostawcy. Jeśli na przykład odczytaliśmy dane kategorii i produktów bezpośrednio z bazy danych, w przeciwieństwie do architektury, prawdopodobnie chcemy pozwolić deweloperowi strony określić bazę danych parametry połączenia Web.config zamiast używać zakodowanej wartości w kodzie dostawcy. Niestandardowy dostawca mapy witryny, który utworzymy w kroku 6, nie zastępuje tej Initialize metody. Przykład użycia Initialize metody można znaleźć w artykule Jeff Prosise s Storing Site Maps w SQL Server artykule.

Krok 6. Tworzenie niestandardowego dostawcy mapy witryny

Aby utworzyć niestandardowego dostawcę mapy witryny, który kompiluje mapę witryny na podstawie kategorii i produktów w bazie danych Northwind, musimy utworzyć klasę rozszerzającą klasę StaticSiteMapProvider. W kroku 1 poprosiłem Cię o dodanie folderu w folderze App_Code — dodaj nową klasę CustomProviders do tego folderu o nazwie NorthwindSiteMapProvider. Dodaj następujący kod do NorthwindSiteMapProvider klasy :

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Web.Caching;
public class NorthwindSiteMapProvider : StaticSiteMapProvider
{
    private readonly object siteMapLock = new object();
    private SiteMapNode root = null;
    public const string CacheDependencyKey = 
        "NorthwindSiteMapProviderCacheDependency";
    public override SiteMapNode BuildSiteMap()
    {
        // Use a lock to make this method thread-safe
        lock (siteMapLock)
        {
            // First, see if we already have constructed the
            // rootNode. If so, return it...
            if (root != null)
                return root;
            // We need to build the site map!
            
            // Clear out the current site map structure
            base.Clear();
            // Get the categories and products information from the database
            ProductsBLL productsAPI = new ProductsBLL();
            Northwind.ProductsDataTable products = productsAPI.GetProducts();
            // Create the root SiteMapNode
            root = new SiteMapNode(
                this, "root", "~/SiteMapProvider/Default.aspx", "All Categories");
            AddNode(root);
            // Create SiteMapNodes for the categories and products
            foreach (Northwind.ProductsRow product in products)
            {
                // Add a new category SiteMapNode, if needed
                string categoryKey, categoryName;
                bool createUrlForCategoryNode = true;
                if (product.IsCategoryIDNull())
                {
                    categoryKey = "Category:None";
                    categoryName = "None";
                    createUrlForCategoryNode = false;
                }
                else
                {
                    categoryKey = string.Concat("Category:", product.CategoryID);
                    categoryName = product.CategoryName;
                }
                SiteMapNode categoryNode = FindSiteMapNodeFromKey(categoryKey);
                // Add the category SiteMapNode if it does not exist
                if (categoryNode == null)
                {
                    string productsByCategoryUrl = string.Empty;
                    if (createUrlForCategoryNode)
                        productsByCategoryUrl = 
                            "~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=" 
                            + product.CategoryID;
                    categoryNode = new SiteMapNode(
                        this, categoryKey, productsByCategoryUrl, categoryName);
                    AddNode(categoryNode, root);
                }
                // Add the product SiteMapNode
                string productUrl = 
                    "~/SiteMapProvider/ProductDetails.aspx?ProductID=" 
                    + product.ProductID;
                SiteMapNode productNode = new SiteMapNode(
                    this, string.Concat("Product:", product.ProductID), 
                    productUrl, product.ProductName);
                AddNode(productNode, categoryNode);
            }
            
            // Add a "dummy" item to the cache using a SqlCacheDependency
            // on the Products and Categories tables
            System.Web.Caching.SqlCacheDependency productsTableDependency = 
                new System.Web.Caching.SqlCacheDependency("NorthwindDB", "Products");
            System.Web.Caching.SqlCacheDependency categoriesTableDependency = 
                new System.Web.Caching.SqlCacheDependency("NorthwindDB", "Categories");
            // Create an AggregateCacheDependency
            System.Web.Caching.AggregateCacheDependency aggregateDependencies = 
                new System.Web.Caching.AggregateCacheDependency();
            aggregateDependencies.Add(productsTableDependency, categoriesTableDependency);
            // Add the item to the cache specifying a callback function
            HttpRuntime.Cache.Insert(
                CacheDependencyKey, DateTime.Now, aggregateDependencies, 
                Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, 
                CacheItemPriority.Normal, 
                new CacheItemRemovedCallback(OnSiteMapChanged));
            // Finally, return the root node
            return root;
        }
    }
    protected override SiteMapNode GetRootNodeCore()
    {
        return BuildSiteMap();
    }
    protected void OnSiteMapChanged(string key, object value, CacheItemRemovedReason reason)
    {
        lock (siteMapLock)
        {
            if (string.Compare(key, CacheDependencyKey) == 0)
            {
                // Refresh the site map
                root = null;
            }
        }
    }
    public DateTime? CachedDate
    {
        get
        {
            return HttpRuntime.Cache[CacheDependencyKey] as DateTime?;
        }
    }
}

Zacznijmy od eksplorowania tej metody klasyBuildSiteMap, która zaczyna się od instrukcjilock . Instrukcja lock umożliwia wprowadzanie tylko jednego wątku naraz, a tym samym serializowanie dostępu do kodu i zapobieganie przechodzeniu dwóch współbieżnych wątków na siebie nawzajem.

Zmienna root na poziomie SiteMapNode klasy służy do buforowania struktury mapy witryny. Gdy mapa witryny jest tworzona po raz pierwszy lub po raz pierwszy po zmodyfikowaniu danych bazowych, root zostanie null utworzona, a struktura mapy lokacji zostanie utworzona. Węzeł główny mapy lokacji jest przypisywany do root podczas procesu budowy, tak aby przy następnym wywołaniu root tej metody nie będzie .null W związku z tym tak długo, jak root nie null jest struktura mapy lokacji zostanie zwrócona do obiektu wywołującego bez konieczności jego ponownego tworzenia.

Jeśli element główny to null, struktura mapy witryny jest tworzona na podstawie informacji o produkcie i kategorii. Mapa witryny jest tworzona przez utworzenie SiteMapNode wystąpień, a następnie utworzenie hierarchii za pomocą wywołań StaticSiteMapProvider metody klasy s AddNode . AddNode wykonuje wewnętrzne księgowanie, przechowując wystąpienia assortowane SiteMapNode w obiekcie Hashtable. Przed rozpoczęciem konstruowania hierarchii zaczniemy od wywołania Clear metody , która czyści elementy z wewnętrznej Hashtableklasy . ProductsBLL Następnie metoda s GetProducts klasy i wynikowe ProductsDataTable są przechowywane w zmiennych lokalnych.

Budowa mapy lokacji rozpoczyna się od utworzenia węzła głównego i przypisania go do rootelementu . Przeciążenie konstruktora użytegoSiteMapNode w tym miejscu i w tym BuildSiteMap miejscu jest przekazywane następujące informacje:

  • Odwołanie do dostawcy mapy witryny (this).
  • KeyS SiteMapNode . Ta wymagana wartość musi być unikatowa dla każdego SiteMapNodeelementu .
  • UrlS SiteMapNode . Url wartość jest opcjonalna, ale jeśli zostanie podana, każda SiteMapNode wartość musi być unikatowa Url .
  • Parametr SiteMapNode s Title, który jest wymagany.

Wywołanie AddNode(root) metody dodaje element SiteMapNoderoot do mapy witryny jako element główny. Następnie każda ProductRow z nich ProductsDataTable jest wyliczana. Jeśli dla bieżącej kategorii produktu istnieje SiteMapNode już element , zostanie przywołyny. W przeciwnym razie zostanie utworzony nowy SiteMapNode element dla kategorii i dodany jako element podrzędny SiteMapNode``root metody za pośrednictwem wywołania AddNode(categoryNode, root) metody. Po znalezieniu lub utworzeniu SiteMapNode odpowiedniego węzła kategorii SiteMapNode tworzony jest element dla bieżącego produktu i dodawany jako element podrzędny kategorii SiteMapNode za pośrednictwem elementu AddNode(productNode, categoryNode). Należy pamiętać, że wartość właściwości kategorii SiteMapNode jest, gdy właściwość produktu UrlSiteMapNode jest przypisana ~/SiteMapNode/ProductDetails.aspx?ProductID=productID.~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryIDUrl

Uwaga

Te produkty, które mają wartość bazy danych NULL dla nich CategoryID , są grupowane w kategorii SiteMapNode , której Title właściwość ma wartość None i której Url właściwość jest ustawiona na pusty ciąg. Postanowiłem ustawić Url pusty ciąg, ponieważ ProductBLL metoda klasy obecnie GetProductsByCategory(categoryID) nie ma możliwości zwrócenia tylko tych produktów z wartością NULLCategoryID . Chcę również zademonstrować, w jaki sposób kontrolki nawigacji renderują element SiteMapNode , który nie ma wartości dla jej Url właściwości. Zachęcam do rozszerzenia tego samouczka tak, aby właściwość None SiteMapNode wskazuje na ProductsByCategory.aspx, ale wyświetla tylko produkty z wartościamiNULLCategoryID.Url

Po utworzeniu mapy lokacji dowolny obiekt jest dodawany do pamięci podręcznej danych przy użyciu zależności pamięci podręcznej SQL od Categories tabel i Products za pośrednictwem AggregateCacheDependency obiektu. Zapoznaliśmy się z użyciem zależności pamięci podręcznej SQL w poprzednim samouczku przy użyciu zależności pamięci podręcznej SQL. Niestandardowy dostawca mapy lokacji używa jednak przeciążenia metody pamięci podręcznej Insert danych, którą jeszcze eksplorowaliśmy. To przeciążenie przyjmuje jako końcowy parametr wejściowy delegat, który jest wywoływany po usunięciu obiektu z pamięci podręcznej. W szczególności przekazujemy nowego CacheItemRemovedCallback delegata , który wskazuje OnSiteMapChanged metodę zdefiniowaną dalej w dół w NorthwindSiteMapProvider klasie.

Uwaga

Reprezentacja mapy lokacji w pamięci jest buforowana za pośrednictwem zmiennej rootna poziomie klasy . Ponieważ istnieje tylko jedno wystąpienie niestandardowej klasy dostawcy mapy witryny i ponieważ to wystąpienie jest współużytkowane między wszystkimi wątkami w aplikacji internetowej, ta zmienna klasy służy jako pamięć podręczna. Metoda BuildSiteMap używa również pamięci podręcznej danych, ale tylko jako środek do odbierania powiadomień, gdy bazowe dane bazy danych w Categories tabelach lub Products się zmieniają. Należy pamiętać, że wartość umieszczona w pamięci podręcznej danych to tylko bieżąca data i godzina. Rzeczywiste dane mapy witryny nie są umieszczane w pamięci podręcznej danych.

Metoda BuildSiteMap zostanie ukończona przez zwrócenie węzła głównego mapy witryny.

Pozostałe metody są dość proste. GetRootNodeCore jest odpowiedzialny za zwracanie węzła głównego. Ponieważ BuildSiteMap zwraca element główny, GetRootNodeCore po prostu zwraca BuildSiteMap wartość zwracaną przez użytkownika. Metoda OnSiteMapChanged jest ustawiana root z powrotem do null momentu usunięcia elementu pamięci podręcznej. Po ponownym ustawieniu elementu głównego na nullwartość , przy następnym BuildSiteMap wywołaniu struktura mapy witryny zostanie ponownie skompilowana. CachedDate Na koniec właściwość zwraca wartość daty i godziny przechowywanej w pamięci podręcznej danych, jeśli taka wartość istnieje. Ta właściwość może służyć deweloperowi strony do określenia, kiedy dane mapy witryny były ostatnio buforowane.

Krok 7. RejestrowanieNorthwindSiteMapProvider

Aby nasza aplikacja internetowa korzystała z dostawcy mapy witryny utworzonego NorthwindSiteMapProvider w kroku 6, musimy zarejestrować ją w <siteMap> sekcji Web.config. W szczególności dodaj następujące znaczniki w elemecie <system.web> w pliku Web.config:

<siteMap defaultProvider="AspNetXmlSiteMapProvider">
  <providers>
    <add name="Northwind" type="NorthwindSiteMapProvider" />
  </providers>
</siteMap>

Ta adiustacja wykonuje dwie czynności: najpierw wskazuje, że wbudowany AspNetXmlSiteMapProvider jest domyślnym dostawcą mapy lokacji; po drugie rejestruje niestandardowego dostawcę mapy witryny utworzonego w kroku 6 z przyjazną dla człowieka nazwą Northwind.

Uwaga

W przypadku dostawców map lokacji znajdujących się w folderze aplikacji App_Code wartość atrybutu type to po prostu nazwa klasy. Alternatywnie niestandardowy dostawca mapy witryny mógł zostać utworzony w osobnym projekcie Biblioteki klas z skompilowanym zestawem umieszczonym w katalogu aplikacji /Bin internetowej. W takim przypadku wartość atrybutu type będzie przestrzeń nazw.ClassName, AssemblyName .

Po zaktualizowaniu Web.configprogramu poświęć chwilę, aby wyświetlić dowolną stronę z samouczków w przeglądarce. Pamiętaj, że interfejs nawigacyjny po lewej stronie nadal zawiera sekcje i samouczki zdefiniowane w pliku Web.sitemap. Dzieje się tak, ponieważ pozostawiliśmy AspNetXmlSiteMapProvider jako dostawcę domyślnego. Aby utworzyć element interfejsu użytkownika nawigacji korzystającego z elementu NorthwindSiteMapProvider, należy jawnie określić, że należy użyć dostawcy mapy witryny Northwind. Zobaczymy, jak to zrobić w kroku 8.

Krok 8. Wyświetlanie informacji o mapie witryny przy użyciu niestandardowego dostawcy mapy lokacji

Za pomocą niestandardowego dostawcy mapy witryny utworzonego i zarejestrowanego w Web.configprogramie możemy dodać kontrolki nawigacji do Default.aspxplików , ProductsByCategory.aspxi ProductDetails.aspx stron w folderze SiteMapProvider . Zacznij od otwarcia Default.aspx strony i przeciągnij element SiteMapPath z przybornika do Projektant. Kontrolka SiteMapPath znajduje się w sekcji Nawigacja przybornika.

Dodawanie ścieżki SiteMapPath do Default.aspx

Rysunek 16. Dodawanie ścieżki SiteMapPath do Default.aspx (kliknij, aby wyświetlić obraz pełnowymiarowy)

Kontrolka SiteMapPath wyświetla link do stron nadrzędnych wskazujący bieżącą lokalizację strony na mapie witryny. Dodaliśmy ścieżkę SiteMapPath w górnej części strony wzorcowej z powrotem w samouczku Strony wzorcowe i Nawigacja po witrynie .

Poświęć chwilę, aby wyświetlić tę stronę za pośrednictwem przeglądarki. Ścieżka SiteMapPath dodana na rysunku 16 używa domyślnego dostawcy mapy witryny, ściągając dane z Web.sitemapelementu . W związku z tym w witrynie nadrzędnym jest wyświetlana > strona główna Dostosowywanie mapy witryny, podobnie jak strona do stron nadrzędnych w prawym górnym rogu.

Usługa Breadcrumb używa domyślnego dostawcy mapy witryny

Rysunek 17. Strona do stron nadrzędnych używa domyślnego dostawcy mapy witryny (kliknij, aby wyświetlić obraz pełnowymiarowy)

Aby obiekt SiteMapPath został dodany na rysunku 16, użyj niestandardowego dostawcy mapy witryny utworzonego w kroku 6, ustaw jej SiteMapProvider właściwość na Northwind, nazwę przypisaną do NorthwindSiteMapProvider elementu w Web.config. Niestety, Projektant nadal używa domyślnego dostawcy mapy witryny, ale jeśli odwiedzasz stronę za pośrednictwem przeglądarki po wprowadzeniu tej zmiany właściwości, zobaczysz, że strona do stron nadrzędnych używa teraz niestandardowego dostawcy mapy witryny.

Zrzut ekranu przedstawiający sposób wyświetlania niestandardowego dostawcy mapy witryny.

Rysunek 18. Strona do stron nadrzędnych używa teraz niestandardowego dostawcy NorthwindSiteMapProvider mapy lokacji (kliknij, aby wyświetlić obraz pełnowymiarowy)

Kontrolka SiteMapPath wyświetla bardziej funkcjonalny interfejs użytkownika na ProductsByCategory.aspx stronach i ProductDetails.aspx . Dodaj ścieżkę SiteMapPath do tych stron, ustawiając SiteMapProvider właściwość w obu polach na Northwind. Kliknij Default.aspx link Wyświetl produkty dla napojów, a następnie na linku Wyświetl szczegóły dla Chai Tea. Jak pokazano na rysunku 19, strona do stron nadrzędnych zawiera bieżącą sekcję mapy witryny (Chai Tea) i jej przodków: Napoje i Wszystkie kategorie.

Zrzut ekranu przedstawiający sposób wyświetlania sekcji mapy bieżącej witryny (Chai Tea) i jej przodków (Napoje i wszystkie kategorie).

Rysunek 19. Strona do stron nadrzędnych używa teraz niestandardowego dostawcy NorthwindSiteMapProvider mapy witryny (kliknij, aby wyświetlić obraz pełnowymiarowy)

Inne elementy interfejsu użytkownika nawigacji można używać oprócz kontrolki SiteMapPath, takich jak kontrolki Menu i TreeView. Strony Default.aspx, ProductsByCategory.aspxi ProductDetails.aspx w pobieraniu dla tego samouczka, na przykład wszystkie kontrolki menu dołączania (zobacz Rysunek 20). Zobacz ASP.NET 2.0 zaawansowane funkcje nawigacji witryny i sekcję Using Site Navigation Controls (Korzystanie z kontrolek nawigacji witryny ) ASP.NET 2.0 Szybki start , aby uzyskać bardziej szczegółowe informacje na temat kontrolek nawigacji i systemu mapy lokacji w ASP.NET 2.0.

Kontrolka menu Listy każdą z kategorii i produktów

Rysunek 20. Kontrolka menu Listy Każdy z kategorii i produktów (kliknij, aby wyświetlić obraz pełnowymiarowy)

Jak wspomniano wcześniej w tym samouczku, struktura mapy witryny może być uzyskiwana programowo za pośrednictwem SiteMap klasy. Poniższy kod zwraca katalog główny SiteMapNode domyślnego dostawcy:

SiteMapNode root = SiteMap.RootNode;

AspNetXmlSiteMapProvider Ponieważ jest to domyślny dostawca naszej aplikacji, powyższy kod zwróci węzeł główny zdefiniowany w pliku Web.sitemap. Aby odwołać się do dostawcy mapy lokacji innego niż domyślny, użyj SiteMap właściwości klasy s Providers w następujący sposób:

SiteMapNode root = SiteMap.Providers["name"].RootNode;

Gdzie nazwa to nazwa niestandardowego dostawcy mapy witryny (Northwind, dla naszej aplikacji internetowej).

Aby uzyskać dostęp do elementu członkowskiego specyficznego dla dostawcy mapy lokacji, użyj polecenia SiteMap.Providers["name"] , aby pobrać wystąpienie dostawcy, a następnie rzutować go do odpowiedniego typu. Aby na przykład wyświetlić NorthwindSiteMapProvider właściwość s CachedDate na stronie ASP.NET, użyj następującego kodu:

NorthwindSiteMapProvider customProvider = 
    SiteMap.Providers["Northwind"] as NorthwindSiteMapProvider;
if (customProvider != null)
{
    DateTime? lastCachedDate = customProvider.CachedDate;
    if (lastCachedDate != null)
        LabelID.Text = "Site map cached on: " + lastCachedDate.Value.ToString();
    else
        LabelID.Text = "The site map is being reconstructed!";
}

Uwaga

Pamiętaj, aby przetestować funkcję zależności pamięci podręcznej SQL. Po przejściu Default.aspxna strony , ProductsByCategory.aspxi ProductDetails.aspx przejdź do jednego z samouczków w sekcji Edytowanie, Wstawianie i Usuwanie oraz edytuj nazwę kategorii lub produktu. Następnie wróć do jednej ze stron w folderze SiteMapProvider . Zakładając, że dla mechanizmu sondowania minęło wystarczająco dużo czasu, aby zanotować zmianę bazowej bazy danych, mapa lokacji powinna zostać zaktualizowana w celu wyświetlenia nowej nazwy produktu lub kategorii.

Podsumowanie

ASP.NET funkcji mapy witryny w wersji 2.0 obejmuje klasę SiteMap , szereg wbudowanych kontrolek sieci Web nawigacji oraz domyślnego dostawcę mapy witryny, który oczekuje, że informacje o mapie witryny zostaną utrwalone w pliku XML. Aby użyć informacji o mapie witryny z innego źródła, takiego jak baza danych, architektura aplikacji lub zdalna usługa sieci Web, musimy utworzyć niestandardowego dostawcę mapy lokacji. Obejmuje to utworzenie klasy, która pochodzi bezpośrednio lub pośrednio z SiteMapProvider klasy.

W tym samouczku pokazano, jak utworzyć niestandardowego dostawcę mapy lokacji, który na podstawie mapy witryny na podstawie informacji o produkcie i kategorii uszczelił z architektury aplikacji. Nasz dostawca rozszerzył klasę StaticSiteMapProvider i wiązał się z utworzeniem BuildSiteMap metody, która pobierała dane, konstruowała hierarchię mapy lokacji i buforowała wynikową strukturę w zmiennej na poziomie klasy. Użyliśmy zależności pamięci podręcznej SQL z funkcją wywołania zwrotnego, aby unieważnić strukturę buforowaną po zmodyfikowaniu bazowych Categories danych lub Products danych.

Szczęśliwe programowanie!

Dalsze informacje

Aby uzyskać więcej informacji na temat tematów omówionych w tym samouczku, zapoznaj się z następującymi zasobami:

Informacje o autorze

Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Można do niego dotrzeć pod adresem mitchell@4GuysFromRolla.com. Lub za pośrednictwem swojego bloga, który można znaleźć na stronie http://ScottOnWriting.NET.

Specjalne podziękowania

Ta seria samouczków została sprawdzona przez wielu pomocnych recenzentów. Recenzenci na potrzeby tego samouczka to Dave Gardner, Zack Jones, Teresa Murphy i Bernadette Leigh. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, upuść mi wiersz pod adresem mitchell@4GuysFromRolla.com.