Sdílet prostřednictvím


Vytvoření vlastního databázově řízeného zprostředkovatele mapy webu (C#)

Scott Mitchell

Stáhnout PDF

Výchozí zprostředkovatel mapy webu v ASP.NET 2.0 načítá data ze statického souboru XML. I když je zprostředkovatel založený na jazyce XML vhodný pro mnoho malých a středně velkých webů, větší webové aplikace vyžadují dynamičtější mapu webu. V tomto kurzu vytvoříme vlastního zprostředkovatele mapy webu, který načítá data z vrstvy obchodní logiky, která pak načítá data z databáze.

Úvod

funkce mapy webu ASP.NET 2.0 umožňuje vývojáři stránek definovat mapu webu webové aplikace v nějakém trvalém médiu, například v souboru XML. Po definování lze k datům mapy webu přistupovat programově prostřednictvím SiteMap třídy v System.Web oboru názvů nebo prostřednictvím různých navigačních webových ovládacích prvků, jako jsou SiteMapPath, Menu a TreeView ovládací prvky. Systém map webů používá model zprostředkovatele, aby bylo možné vytvořit a připojit do webové aplikace různé implementace serializace map webů. Výchozí zprostředkovatel mapy webu, který se dodává s ASP.NET 2.0, zachová strukturu mapy webu v souboru XML. Zpět v kurzu Stránky předlohy a Navigace na webu jsme vytvořili soubor s názvem Web.sitemap , který obsahoval tuto strukturu a aktualizovali jeho XML s každou novou částí kurzu.

Výchozí zprostředkovatel mapování webů založený na jazyce XML funguje dobře, pokud je struktura mapy webu poměrně statická, například pro tyto kurzy. V mnoha scénářích je ale potřeba dynamičtější mapa webu. Představte si mapu webu zobrazenou na obrázku 1, kde se každá kategorie a produkt zobrazují jako oddíly ve struktuře webu. Při použití této mapy webu může návštěva webové stránky odpovídající kořenovému uzlu vypsat všechny kategorie, zatímco při návštěvě webové stránky konkrétní kategorie by se zobrazil seznam produktů dané kategorie a zobrazením webové stránky konkrétního produktu by se zobrazily podrobnosti o produktu.

Kategorie a produkty– make-up struktury mapy webu

Obrázek 1: Kategorie a produkty– struktura mapy webu (kliknutím zobrazíte obrázek v plné velikosti)

I když by tato struktura založená na kategoriích a produktech mohla být pevně zakódovaná do Web.sitemap souboru, je potřeba soubor aktualizovat při každém přidání, odebrání nebo přejmenování kategorie nebo produktu. V důsledku toho by byla údržba mapy webu značně zjednodušena, pokud by její struktura byla načtena z databáze nebo v ideálním případě z vrstvy obchodní logiky architektury aplikace. Při přidání, přejmenování nebo odstranění produktů a kategorií se pak mapa webu automaticky aktualizuje tak, aby odrážela tyto změny.

Vzhledem k tomu, že serializace mapy webu ASP.NET 2.0 je postavena na základě modelu zprostředkovatele, můžeme vytvořit vlastního zprostředkovatele mapy webu, který vezme data z alternativního úložiště dat, jako je databáze nebo architektura. V tomto kurzu sestavíme vlastního zprostředkovatele, který načítá data z BLL. Pusťme se do toho!

Poznámka

Vlastní zprostředkovatel map webů vytvořený v tomto kurzu je úzce svázán s architekturou a datovým modelem aplikace. Jeff Prosise: Ukládání map webů v SQL Server a Zprostředkovatel map webů SQL, na které jste čekali, se zkoumají zobecněný přístup k ukládání dat mapy webu v SQL Server.

Krok 1: Vytvoření vlastních webových stránek zprostředkovatele map webů

Než začneme vytvářet vlastního zprostředkovatele map webů, pojďme nejdřív přidat ASP.NET stránky, které budeme pro účely tohoto kurzu potřebovat. Začněte přidáním nové složky s názvem SiteMapProvider. Dále do této složky přidejte následující ASP.NET stránky a nezapomeňte každou stránku přidružit ke Site.master stránce předlohy:

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

Do složky také přidejte CustomProviders podsložku App_Code .

Přidání stránek ASP.NET pro kurzy map Provider-Related webu

Obrázek 2: Přidání ASP.NET stránek pro kurzy map Provider-Related webu

Vzhledem k tomu, že pro tuto část existuje pouze jeden kurz, nemusíme Default.aspx vypisovat kurzy oddílů. Default.aspx Místo toho zobrazí kategorie v GridView ovládací prvek. Budeme se tím zabývat v kroku 2.

Dále aktualizujte Web.sitemap tak, aby obsahovala odkaz na Default.aspx stránku. Konkrétně přidejte následující kód za ukládání do mezipaměti <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 aktualizaci Web.sitemapse chvíli podívejte na web kurzů prostřednictvím prohlížeče. Nabídka na levé straně teď obsahuje položku pro kurz o jediném poskytovateli map webů.

Mapa webu teď obsahuje položku pro kurz ke zprostředkovateli map webů.

Obrázek 3: Mapa webu teď obsahuje položku pro kurz ke zprostředkovateli map webů

Tento kurz se zaměřuje hlavně na ilustraci vytvoření vlastního zprostředkovatele mapy webu a konfigurace webové aplikace pro použití tohoto zprostředkovatele. Konkrétně vytvoříme zprostředkovatele, který vrátí mapu webu, která obsahuje kořenový uzel spolu s uzlem pro každou kategorii a produkt, jak je znázorněno na obrázku 1. Obecně platí, že každý uzel v mapě webu může zadat adresu URL. V mapě webu bude ~/SiteMapProvider/Default.aspxadresa URL kořenového uzlu , která zobrazí seznam všech kategorií v databázi. Každý uzel kategorie v mapě webu bude mít adresu URL odkazující na ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID, která zobrazí seznam všech produktů v zadaném id kategorie. Nakonec bude každý uzel mapy webu produktu odkazovat na ~/SiteMapProvider/ProductDetails.aspx?ProductID=productID, který zobrazí podrobnosti o konkrétním produktu.

Abychom mohli začít, musíme vytvořit Default.aspxstránky , ProductsByCategory.aspxa ProductDetails.aspx . Tyto stránky se dokončí v krocích 2, 3 a 4. Vzhledem k tomu, že podstata tohoto kurzu je na poskytovatelích map webů a vzhledem k tomu, že předchozí kurzy se zabývaly vytvářením těchto typů vícestránkových řídicích/podrobných sestav, pospíšíme si kroky 2 až 4. Pokud si potřebujete zopakovat vytváření hlavních nebo podrobných sestav, které pokrývají více stránek, projděte si kurz Filtrování předlohy/podrobností na dvou stránkách .

Krok 2: Zobrazení seznamu kategorií

Default.aspx Otevřete stránku ve SiteMapProvider složce a přetáhněte objekt GridView z panelu nástrojů na Designer s nastavením ID na Categories. Z inteligentní značky GridView vytvořte vazbu na nový ObjectDataSource s názvem CategoriesDataSource a nakonfigurujte ji tak, aby načítala data pomocí CategoriesBLL metody třídy s GetCategories . Vzhledem k tomu, že tento objekt GridView pouze zobrazuje kategorie a neposkytuje možnosti úprav dat, nastavte rozevírací seznamy na kartách UPDATE, INSERT a DELETE na (None) .

Nakonfigurujte ObjektDataSource tak, aby vracel kategorie pomocí metody GetCategories.

Obrázek 4: Konfigurace objektu ObjectDataSource tak, aby vracel kategorie pomocí GetCategories metody (kliknutím zobrazíte obrázek v plné velikosti)

Nastavte Drop-Down Seznamy na kartách AKTUALIZOVAT, VLOŽIT a ODSTRANIT na (Žádné).

Obrázek 5: Nastavte Drop-Down Seznamy na kartách UPDATE (UPDATE), INSERT a DELETE (Žádný) (Kliknutím zobrazíte obrázek v plné velikosti)

Po dokončení průvodce Konfigurací zdroje dat přidá Visual Studio BoundField pro CategoryID, CategoryName, Description, NumberOfProductsa BrochurePath. Upravte Objekt GridView tak, aby obsahoval CategoryName pouze a Description BoundFields, a aktualizujte CategoryName vlastnost BoundField s HeaderText na Category .

Dále přidejte pole HyperLinkField a umístěte ho tak, aby se jedná o pole nejvíce vlevo. Vlastnost nastavte DataNavigateUrlFields na CategoryID a vlastnost DataNavigateUrlFormatString na ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}. Vlastnost nastavte Text na View Products (Zobrazit produkty).

Přidání HyperLinkField do objektu Categories GridView

Obrázek 6: Přidání HyperLinkField do objektu Categories GridView

Po vytvoření ObjectDataSource a přizpůsobení polí GridView s budou deklarativní značky dvou ovládacích prvků vypadat takto:

<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>

Obrázek 7 ukazuje Default.aspx zobrazení v prohlížeči. Kliknutím na odkaz na kategorii Zobrazit produkty přejdete na ProductsByCategory.aspx?CategoryID=categoryID, který vytvoříme v kroku 3.

Každá kategorie je uvedená společně s odkazem Zobrazit produkty.

Obrázek 7: Každá kategorie je uvedená společně s odkazem Zobrazit produkty (kliknutím zobrazíte obrázek v plné velikosti)

Krok 3: Výpis vybraných produktů kategorie

ProductsByCategory.aspx Otevřete stránku a přidejte Objekt GridView s pojmenováním ProductsByCategory. Ze své inteligentní značky vytvořte vazbu objektu GridView na nový objekt ObjectDataSource s názvem ProductsByCategoryDataSource. Nakonfigurujte ObjectDataSource tak, aby používal metodu ProductsBLL třídy s GetProductsByCategoryID(categoryID) , a nastavte rozevírací seznamy na (None) na kartách UPDATE, INSERT a DELETE.

Použití metody GetProductsByCategoryID(categoryID) třídy ProductsBLL

Obrázek 8: Použití ProductsBLL metody Třídy GetProductsByCategoryID(categoryID) s (kliknutím zobrazíte obrázek v plné velikosti)

V posledním kroku průvodce Konfigurovat zdroj dat se zobrazí výzva k zadání zdroje parametrů pro categoryID. Vzhledem k tomu, že se tyto informace předávají přes pole CategoryIDřetězce dotazu, vyberte v rozevíracím seznamu Řetězec dotazu a do textového pole QueryStringField zadejte CategoryID, jak je znázorněno na obrázku 9. Dokončete průvodce kliknutím na Dokončit.

Použití pole Řetězec dotazu CategoryID pro parametr categoryID

Obrázek 9: Použití CategoryID pole řetězce dotazu pro parametr categoryID (kliknutím zobrazíte obrázek v plné velikosti)

Po dokončení průvodce visual Studio přidá odpovídající BoundFields a CheckBoxField do GridView pro pole dat produktu. Odeberte všechna pole kromě ProductName, UnitPricea SupplierName BoundField. Přizpůsobte tyto tři vlastnosti BoundFields tak, aby četly HeaderText informace o produktu, ceně a dodavateli v uvedeném pořadí. Naformátujte UnitPrice BoundField jako měnu.

Dále přidejte Pole HyperLinkField a přesuňte ho na pozici úplně vlevo. Nastavte jeho Text vlastnost na View Details (Zobrazit podrobnosti), nastavte vlastnost DataNavigateUrlFields na ProductIDa nastavte vlastnost DataNavigateUrlFormatString na ~/SiteMapProvider/ProductDetails.aspx?ProductID={0}.

Přidání pole HyperLinkField podrobností zobrazení, které odkazuje na ProductDetails.aspx

Obrázek 10: Přidání pole HyperLinkField podrobností zobrazení, které odkazuje na ProductDetails.aspx

Po provedení těchto přizpůsobení by deklarativní značky GridView a ObjectDataSource měly vypadat takto:

<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>

Vraťte se do zobrazení Default.aspx v prohlížeči a klikněte na odkaz Zobrazit produkty pro nápoje. Tím přejdete na ProductsByCategory.aspx?CategoryID=1, kde se zobrazí názvy, ceny a dodavatelé produktů v databázi Northwind, které patří do kategorie Nápoje (viz Obrázek 11). Tuto stránku můžete dále vylepšit tak, aby obsahovala odkaz pro návrat uživatelů na stránku se seznamem kategorií (Default.aspx) a ovládací prvek DetailsView nebo FormView, který zobrazuje název a popis vybrané kategorie.

Zobrazí se názvy nápojů, ceny a dodavatelé.

Obrázek 11: Zobrazí se názvy nápojů, ceny a dodavatelé (kliknutím zobrazíte obrázek v plné velikosti).

Krok 4: Zobrazení podrobností o produktu

Na poslední stránce se ProductDetails.aspxzobrazí podrobnosti o vybraných produktech. Otevřete ProductDetails.aspx a přetáhněte zobrazení DetailsView z panelu nástrojů do Designer. Nastavte vlastnost DetailsView s ID na ProductInfo a vymažte její Height hodnoty a Width vlastnosti. Ze své inteligentní značky vytvořte vazbu DetailsView na nový ObjectDataSource s názvem ProductDataSourcea nakonfigurujte ObjectDataSource tak, aby načítá data z ProductsBLL metody třídy s GetProductByProductID(productID) . Stejně jako u předchozích webových stránek vytvořených v krocích 2 a 3 nastavte rozevírací seznamy na kartách UPDATE, INSERT a DELETE na (Žádné) .

Konfigurace objektu ObjectDataSource na použití metody GetProductByProductID(productID)

Obrázek 12: Konfigurace objektu ObjectDataSource pro použití GetProductByProductID(productID) metody (kliknutím zobrazíte obrázek v plné velikosti)

V posledním kroku průvodce Konfigurací zdroje dat se zobrazí výzva k zadání zdroje parametru productID . Vzhledem k tomu, že tato data přicházejí přes pole ProductIDřetězce dotazu, nastavte rozevírací seznam na QueryString a textové pole QueryStringField na Idproduktu. Nakonec průvodce dokončete kliknutím na tlačítko Dokončit.

Konfigurace parametru productID pro načtení hodnoty z pole řetězce dotazu ProductID

Obrázek 13: Konfigurace parametru productID pro načtení hodnoty z ProductID pole Řetězce dotazu (kliknutím zobrazíte obrázek v plné velikosti)

Po dokončení průvodce Konfigurovat zdroj dat vytvoří Visual Studio odpovídající BoundFields a CheckBoxField v zobrazení DetailsView pro pole s daty produktu. Odeberte pole ProductID, SupplierIDa CategoryID BoundFields a podle potřeby nakonfigurujte zbývající pole. Po několika estetických konfiguracích moje deklarativní značky DetailsView a ObjectDataSource vypadaly takto:

<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>

Pokud chcete tuto stránku otestovat, vraťte se na Default.aspx stránku a klikněte na Zobrazit produkty v kategorii Nápoje. V seznamu nápojových produktů klikněte na odkaz Zobrazit podrobnosti pro Čaj Chai. Tím přejdete na ProductDetails.aspx?ProductID=1, který zobrazuje podrobnosti o čaji Chai (viz obrázek 14).

Zobrazí se informace o dodavateli Chai Tea s, kategorii, ceně a další informace

Obrázek 14: Zobrazí se informace o dodavateli, kategorii, ceně a dalších informacích (kliknutím zobrazíte obrázek v plné velikosti)

Krok 5: Pochopení vnitřního fungování poskytovatele mapy webu

Mapa webu je v paměti webového serveru reprezentována jako kolekce SiteMapNode instancí, které tvoří hierarchii. Musí existovat přesně jeden kořenový uzel, všechny jiné než kořenové uzly musí mít přesně jeden nadřazený uzel a všechny uzly můžou mít libovolný počet podřízených uzlů. Každý SiteMapNode objekt představuje oddíl ve struktuře webu. Tyto oddíly mají obvykle odpovídající webovou stránku. V důsledku toho má třída vlastnosti jako Title, Urla Description, které poskytují informace pro oddíl, který SiteMapNode představuje.SiteMapNode Existuje také Key vlastnost, která jedinečně identifikuje každou SiteMapNode z těchto hierarchií, a také vlastnosti použité k vytvoření této hierarchie ChildNodes, ParentNode, NextSibling, PreviousSiblingatd.

Obrázek 15 znázorňuje obecnou strukturu mapy webu z obrázku 1, ale s podrobnějšími podrobnostmi o implementaci.

Každý uzel SiteMapNode má vlastnosti, jako je název, adresa URL, klíč atd.

Obrázek 15: Každý z nich SiteMapNode má vlastnosti, jako jsou Title, UrlKey, a tak dále (kliknutím zobrazíte obrázek v plné velikosti)

Mapa webu je přístupná prostřednictvím SiteMap třídy v System.Web oboru názvů. Tato vlastnost třídy RootNode s vrátí kořenovou SiteMapNode instanci mapy webu. CurrentNode Vrátí SiteMapNode vlastnost, jejíž Url vlastnost odpovídá adrese URL aktuálně požadované stránky. Tuto třídu interně používají ASP.NET 2.0 s navigační webové ovládací prvky.

Při přístupu k SiteMap vlastnostem třídy s musí serializovat strukturu mapy webu z nějakého trvalého média do paměti. Logika serializace mapy webu však není pevně zakódována do SiteMap třídy. Místo toho za běhu SiteMap třída určuje, který zprostředkovatele mapy webu se má použít pro serializaci. Ve výchozím nastavení XmlSiteMapProvider se používá třída, která čte strukturu mapy webu ze správně naformátovaného souboru XML. S trochou práce ale můžeme vytvořit vlastního poskytovatele map webů.

Všichni zprostředkovatelé mapy webu musí být odvozeni od SiteMapProvider třídy, která zahrnuje základní metody a vlastnosti potřebné pro zprostředkovatele mapy webu, ale vynechá mnoho podrobností o implementaci. Druhá třída, StaticSiteMapProvider, rozšiřuje SiteMapProvider třídu a obsahuje robustnější implementaci potřebných funkcí. Interně StaticSiteMapProvider ukládá SiteMapNode instance mapy webu v objektu Hashtable a poskytuje metody, jako je AddNode(child, parent), RemoveNode(siteMapNode), a Clear() které přidávají a odebíraly SiteMapNode objekty s do interního Hashtableobjektu . XmlSiteMapProvider je odvozeno od StaticSiteMapProvider.

Při vytváření vlastního zprostředkovatele mapy webu, který rozšiřuje StaticSiteMapProvider, je potřeba přepsat dvě abstraktní metody: BuildSiteMap a GetRootNodeCore. BuildSiteMap, jak název napovídá, zodpovídá za načtení struktury mapy webu z trvalého úložiště a její vytvoření v paměti. GetRootNodeCore vrátí kořenový uzel v mapě webu.

Aby webová aplikace mohl používat zprostředkovatele mapy webu, musí být zaregistrovaná v konfiguraci aplikace. Ve výchozím nastavení XmlSiteMapProvider je třída registrována pomocí názvu AspNetXmlSiteMapProvider. Pokud chcete zaregistrovat další zprostředkovatele mapy webu, přidejte následující kód do Web.config:

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

Hodnota názvu přiřadí zprostředkovateli název čitelný pro člověka, zatímco typ určuje plně kvalifikovaný název typu poskytovatele mapy webu. Po vytvoření vlastního poskytovatele mapy webu prozkoumáme konkrétní hodnoty názvů a typů v kroku 7.

Třída zprostředkovatele mapy webu se vytvoří při prvním přístupu z SiteMap třídy a zůstane v paměti po celou dobu životnosti webové aplikace. Vzhledem k tomu, že existuje pouze jedna instance zprostředkovatele mapy webu, která může být vyvolána z více souběžných návštěvníků webu, je nezbytné, aby metody zprostředkovatele byly bezpečné pro přístup z více vláken.

Z důvodů výkonu a škálovatelnosti je důležité ukládat strukturu mapy webu v paměti do mezipaměti a vracet tuto strukturu v mezipaměti, nikoli ji znovu vytvořit při BuildSiteMap každém vyvolání metody. BuildSiteMap v závislosti na navigačních ovládacích prvcích, které se používají na stránce a na hloubce struktury mapy webu, může být volána několikrát na jednu stránku. V každém případě, pokud neulovíme strukturu mapy webu do BuildSiteMap mezipaměti, pak pokaždé, když je vyvolána, budeme muset znovu načíst informace o produktu a kategorii z architektury (což by vedlo k dotazu do databáze). Jak jsme probrali v předchozích kurzech ukládání do mezipaměti, data uložená v mezipaměti můžou být zastaralá. V boji proti tomu můžeme použít vypršení platnosti založených na časových závislostech nebo na mezipamětí SQL.

Poznámka

Zprostředkovatel mapy webu může volitelně přepsat metoduInitialize. Initialize se vyvolá při prvním vytvoření instance zprostředkovatele mapy webu a předají se mu všechny vlastní atributy přiřazené zprostředkovateli v Web.config elementu <add> , například : <add name="name" type="type" customAttribute="value" />. Je to užitečné, pokud chcete vývojáři stránky povolit, aby zadal různá nastavení související se zprostředkovatele mapy webu, aniž by bylo nutné upravovat kód zprostředkovatele. Pokud bychom například načítali data kategorií a produktů přímo z databáze, a ne prostřednictvím architektury, pravděpodobně bychom chtěli, aby vývojář stránky zadal databázi připojovací řetězec a Web.config nepoužívali pevně zakódovanou hodnotu v kódu zprostředkovatele. Vlastní zprostředkovatel mapy webu, který vytvoříme v kroku 6, tuto Initialize metodu nepřepíše. Příklad použití Initialize metody najdete v článku o ukládání map webu Jeffa Prosisehov SQL Server článku.

Krok 6: Vytvoření vlastního zprostředkovatele mapy webu

Pokud chcete vytvořit vlastního zprostředkovatele mapy webu, který sestaví mapu webu z kategorií a produktů v databázi Northwind, musíme vytvořit třídu, která rozšiřuje StaticSiteMapProvider. V kroku 1 jsem vás požádal o CustomProviders přidání složky do App_Code složky – přidání nové třídy do této složky s názvem NorthwindSiteMapProvider. Do třídy přidejte následující kód NorthwindSiteMapProvider :

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?;
        }
    }
}

Začněme prozkoumáním této metody třídy sBuildSiteMap, která začíná příkazemlock. Příkaz lock umožňuje zadat pouze jedno vlákno najednou, čímž serializuje přístup ke svému kódu a brání dvěma souběžným vláknům v krokování na sebe s prsty.

Proměnná root na úrovni SiteMapNode třídy se používá k ukládání struktury mapy webu do mezipaměti. Při prvním vytvoření mapy webu nebo poprvé po úpravě rootnull podkladových dat se vytvoří struktura mapy webu. Kořenový uzel mapy webu je přiřazen root během procesu výstavby, takže při příštím zavolání root této metody nebude null. V důsledku toho bude struktura mapy webu vrácena volajícímu, rootnull aniž by ji bylo nutné znovu vytvořit.

Pokud je nullkořen kořenem , vytvoří se struktura mapy webu z informací o produktu a kategorii. Mapa webu je vytvořena vytvořením SiteMapNode instancí a následným vytvořením hierarchie prostřednictvím volání StaticSiteMapProvider metody třídy s AddNode . AddNode provádí interní účetnictví a ukládá různé SiteMapNode instance do Hashtable. Než začneme vytvářet hierarchii, začneme voláním Clear metody, která vymaže prvky z interní Hashtable. Dále je ProductsBLL metoda třídy s GetProducts a výsledná ProductsDataTable uložena v místních proměnných.

Vytvoření mapy webu začíná vytvořením kořenového uzlu a jeho přiřazením k root. Přetížení konstruktoru s použitéhoSiteMapNode zde a v tomto BuildSiteMap průběhu je předáno následující informace:

  • Odkaz na zprostředkovatele mapy webu (this).
  • KeyS SiteMapNode . Tato požadovaná hodnota musí být jedinečná pro každou SiteMapNodehodnotu .
  • UrlS SiteMapNode . Url je nepovinný, ale pokud je zadaný, každá SiteMapNode hodnota s Url musí být jedinečná.
  • TitleS SiteMapNode , který je povinný.

Volání AddNode(root) metody přidá SiteMapNoderoot do mapy webu jako kořen. Dále se vyčíslí ProductsDataTable každý ProductRow z nich. Pokud již existuje SiteMapNode kategorie aktuálního produktu, odkazuje se na ni. V opačném případě se vytvoří nový SiteMapNode objekt pro kategorii a přidá se jako podřízený objekt SiteMapNode``root volání metody prostřednictvím AddNode(categoryNode, root) metody. Po nalezení nebo vytvoření SiteMapNode příslušného uzlu kategorie SiteMapNode se vytvoří uzel pro aktuální produkt a přidá se jako podřízený uzel kategorie SiteMapNode prostřednictvím AddNode(productNode, categoryNode). Všimněte si, že hodnota vlastnosti s kategorie SiteMapNodeUrl je ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID v době, kdy je vlastnost produktu UrlSiteMapNode přiřazena ~/SiteMapNode/ProductDetails.aspx?ProductID=productID.

Poznámka

Produkty, které mají hodnotu databáze NULL pro své CategoryID jsou seskupeny do kategorie SiteMapNode , jejíž Title vlastnost je nastavena na None a jejichž Url vlastnost je nastavena na prázdný řetězec. Rozhodl(a) jsem se nastavit Url na prázdný řetězec, protože ProductBLL metoda třídy s GetProductsByCategory(categoryID) v současné době nemá schopnost vrátit pouze ty produkty s NULLCategoryID hodnotou. Také jsem chtěl ukázat, jak navigační ovládací prvky vykreslují SiteMapNode objekt, který nemá hodnotu pro jeho Url vlastnost. Doporučuji vám rozšířit tento kurz tak, že none SiteMapNode s Url vlastnost odkazuje na ProductsByCategory.aspx, ale zobrazuje pouze produkty s NULLCategoryID hodnotami.

Po vytvoření mapy webu se do mezipaměti dat přidá libovolný objekt pomocí závislosti mezipaměti SQL na Categories tabulkách a Products prostřednictvím objektu AggregateCacheDependency . Použití závislostí mezipaměti SQL jsme prozkoumali v předchozím kurzu Používání závislostí mezipaměti SQL. Vlastní poskytovatel mapy webu ale používá přetížení metody mezipaměti dat, Insert kterou jsme ještě nezkoumali. Toto přetížení přijímá jako konečný vstupní parametr delegáta, který je volána při odebrání objektu z mezipaměti. Konkrétně předáme nového CacheItemRemovedCallback delegáta , který odkazuje na metodu definovanou OnSiteMapChanged dále ve NorthwindSiteMapProvider třídě.

Poznámka

Reprezentace mapy webu v paměti se ukládá do mezipaměti prostřednictvím proměnné rootna úrovni třídy . Vzhledem k tomu, že existuje pouze jedna instance vlastní třídy zprostředkovatele mapy webu a protože tato instance je sdílena mezi všechna vlákna ve webové aplikaci, slouží tato proměnná třídy jako mezipaměť. Metoda BuildSiteMap také používá mezipaměť dat, ale pouze jako prostředek k přijetí oznámení při změně podkladových databázových dat v Categories tabulkách nebo Products . Všimněte si, že hodnota vložená do mezipaměti dat je pouze aktuální datum a čas. Skutečná data mapy webu se do mezipaměti dat neumisťuje.

Metoda se BuildSiteMap dokončí vrácením kořenového uzlu mapy webu.

Zbývající metody jsou poměrně jednoduché. GetRootNodeCore zodpovídá za vrácení kořenového uzlu. Vzhledem k tomu BuildSiteMap , že vrátí kořen, GetRootNodeCore vrátí BuildSiteMap jednoduše návratovou hodnotu s. Metoda OnSiteMapChanged se nastaví root zpět na null při odebrání položky mezipaměti. S kořenem nastaveným zpět na null, při BuildSiteMap příštím vyvolání bude struktura mapy webu znovu vytvořena. CachedDate Nakonec vlastnost vrátí hodnotu data a času uloženou v mezipaměti dat, pokud taková hodnota existuje. Tuto vlastnost může použít vývojář stránky k určení, kdy byla data mapy webu naposledy uložena do mezipaměti.

Krok 7: RegistraceNorthwindSiteMapProvider

Aby naše webová aplikace mohla používat zprostředkovatele mapy webu vytvořeného NorthwindSiteMapProvider v kroku 6, musíme ho zaregistrovat v <siteMap> části Web.config. Konkrétně přidejte následující kód v elementu <system.web> v Web.config:

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

Tento kód dělá dvě věci: zaprvé označuje, že předdefinovaný AspNetXmlSiteMapProvider je výchozí zprostředkovatel mapy webu; za druhé zaregistruje vlastního zprostředkovatele mapy webu vytvořeného v kroku 6 s názvem Northwind.

Poznámka

U zprostředkovatelů mapy webu umístěných ve složce s App_Code aplikace je hodnotou atributu type jednoduše název třídy. Případně může být vlastní zprostředkovatel mapy webu vytvořen v samostatném projektu knihovny tříd s kompilovaným sestavením umístěným v adresáři s /Bin webové aplikace. V takovém případě by hodnota atributu typebyla Obor názvů.ClassName, AssemblyName .

Po aktualizaci Web.configse chvíli podívejte na libovolnou stránku z kurzů v prohlížeči. Všimněte si, že navigační rozhraní na levé straně stále zobrazuje oddíly a kurzy definované v Web.sitemapnástroji . Je to proto, že jsme opustili AspNetXmlSiteMapProvider výchozího poskytovatele. Abychom mohli vytvořit prvek navigačního uživatelského rozhraní, který používá NorthwindSiteMapProvider, budeme muset explicitně určit, že se má použít zprostředkovatele mapy webu Northwind. Jak toho dosáhnout, uvidíme v kroku 8.

Krok 8: Zobrazení informací o mapě webu pomocí vlastního zprostředkovatele mapy webu

Po vytvoření a registraci vlastního zprostředkovatele mapy webu v Web.confignástroji jsme připraveni přidat navigační ovládací prvky na Default.aspxstránky , ProductsByCategory.aspxa ProductDetails.aspx ve SiteMapProvider složce. Začněte otevřením Default.aspx stránky a přetažením SiteMapPath ze sady nástrojů na Designer. Ovládací prvek SiteMapPath se nachází v části Navigace panelu nástrojů.

Přidání cesty SiteMapPath do Default.aspx

Obrázek 16: Přidání siteMapPath do Default.aspx (Kliknutím zobrazíte obrázek v plné velikosti)

Ovládací prvek SiteMapPath zobrazí popis cesty označující aktuální umístění stránky v mapě webu. V kurzu Stránky předlohy a Navigace na webu jsme do horní části stránky předlohy přidali cestu SiteMapPath.

Chvíli si tuto stránku prohlédněte v prohlížeči. SiteMapPath přidaná na obrázku 16 používá výchozího zprostředkovatele mapy webu a získává data z Web.sitemap. Proto popis cesty zobrazuje domovskou > stránku Přizpůsobení mapy webu stejně jako popis cesty v pravém horním rohu.

Popis cesty používá výchozího zprostředkovatele mapy webu.

Obrázek 17: Popis cesty používá výchozího zprostředkovatele mapy webu (kliknutím zobrazíte obrázek v plné velikosti)

Pokud chcete, aby cesta SiteMapPath přidaná na obrázku 16 používala vlastního zprostředkovatele mapy webu, který jsme vytvořili v kroku 6, nastavte jeho SiteMapProvider vlastnost na Northwind, název, který jsme přiřadili k objektu NorthwindSiteMapProvider v Web.config. Designer bohužel dál používá výchozího poskytovatele mapy webu, ale pokud po provedení této změny vlastnosti navštívíte stránku přes prohlížeč, uvidíte, že popis cesty teď používá vlastního poskytovatele mapy webu.

Snímek obrazovky znázorňující, jak popis cesty zobrazuje vlastního poskytovatele mapy webu

Obrázek 18: Popis cesty teď používá vlastního zprostředkovatele NorthwindSiteMapProvider mapy webu (kliknutím zobrazíte obrázek v plné velikosti)

Ovládací prvek SiteMapPath zobrazí na ProductsByCategory.aspx stránkách a ProductDetails.aspx funktivnější uživatelské rozhraní. Přidejte na tyto stránky SiteMapPath a SiteMapProvider vlastnost v obou nastavíte na Northwind. V Default.aspx části Nápoje klikněte na odkaz Zobrazit produkty a pak klikněte na odkaz Zobrazit podrobnosti pro Čaj Chai. Jak ukazuje obrázek 19, popis cesty obsahuje aktuální část mapy webu (Chai Tea) a její předky: Nápoje a všechny kategorie .

Snímek obrazovky znázorňující, jak popis cesty zobrazuje aktuální sekci mapy webu (Chai Tea) a jeho předchůdce (Nápoje a všechny kategorie)

Obrázek 19: Popis cesty teď používá vlastního zprostředkovatele NorthwindSiteMapProvider mapy webu (kliknutím zobrazíte obrázek v plné velikosti)

Další prvky uživatelského rozhraní navigace lze použít kromě SiteMapPath, například Menu a TreeView ovládací prvky. Stránky Default.aspx, ProductsByCategory.aspxa ProductDetails.aspx ve stažení pro tento kurz, například všechny zahrnují ovládací prvky Nabídky (viz Obrázek 20). Podrobnější informace o ovládacích prvcích navigace a systému mapy webu v ASP.NET 2.0 najdete v části Sofistikované funkce navigace na webu ASP.NET 2.0 a Používání ovládacích prvků navigace na webu v ASP.NET 2.0 .

Ovládací prvek Menu Seznamy Jednotlivé kategorie a produkty

Obrázek 20: Ovládací prvek nabídky Seznamy každou z kategorií a produktů (kliknutím zobrazíte obrázek v plné velikosti)

Jak je uvedeno dříve v tomto kurzu, ke struktuře mapy webu je možné přistupovat programově prostřednictvím SiteMap třídy. Následující kód vrátí kořen výchozího SiteMapNode zprostředkovatele:

SiteMapNode root = SiteMap.RootNode;

Vzhledem k tomu, že AspNetXmlSiteMapProvider je výchozí zprostředkovatel pro naši aplikaci, výše uvedený kód vrátí kořenový uzel definovaný v nástroji Web.sitemap. Pokud chcete odkazovat na jiného poskytovatele mapy webu, než je výchozí, použijte SiteMap vlastnost třídy s Providers následujícím způsobem:

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

Kde název je název vlastního zprostředkovatele mapy webu (Northwind, pro naši webovou aplikaci).

Pokud chcete získat přístup k členu specifickému pro zprostředkovatele mapy webu, použijte SiteMap.Providers["name"] k načtení instance zprostředkovatele a pak ji přetypujte na příslušný typ. Pokud chcete například zobrazit NorthwindSiteMapProvider vlastnost s CachedDate na stránce ASP.NET, použijte následující kód:

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!";
}

Poznámka

Nezapomeňte otestovat funkci závislostí mezipaměti SQL. Po návštěvě Default.aspxstránek , ProductsByCategory.aspxa ProductDetails.aspx přejděte na jeden z kurzů v části Úpravy, vkládání a odstraňování a upravte název kategorie nebo produktu. Pak se vraťte na jednu ze stránek ve SiteMapProvider složce. Za předpokladu, že uplynul dostatek času, aby mechanismus dotazování zaznamenal změnu v podkladové databázi, měla by se mapa webu aktualizovat tak, aby zobrazovala nový název produktu nebo kategorie.

Souhrn

funkce mapy webu ASP.NET 2.0 s zahrnují SiteMap třídu, řadu předdefinovaných navigačních webových ovládacích prvků a výchozího zprostředkovatele mapy webu, který očekává, že informace o mapě webu zůstanou zachovány v souboru XML. Abychom mohli používat informace o mapě webu z nějakého jiného zdroje, například z databáze, architektury aplikace nebo vzdálené webové služby, musíme vytvořit vlastního zprostředkovatele mapy webu. To zahrnuje vytvoření třídy, která je odvozena, přímo nebo nepřímo, z SiteMapProvider třídy.

V tomto kurzu jsme viděli, jak vytvořit vlastního zprostředkovatele mapy webu, který mapu webu založí na informacích o produktech a kategoriích, které jsou vytříděné z architektury aplikace. Náš zprostředkovatel rozšířil StaticSiteMapProvider třídu a zahrnoval vytvoření BuildSiteMap metody, která načetla data, vytvořila hierarchii mapy webu a výslednou strukturu do mezipaměti v proměnné na úrovni třídy. Použili jsme závislost mezipaměti SQL s funkcí zpětného volání k zneplatnění struktury uložené v mezipaměti při úpravě podkladových Categories dat nebo Products dat.

Šťastné programování!

Další čtení

Další informace o tématech probíraných v tomto kurzu najdete v následujících zdrojích informací:

O autorovi

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

Zvláštní poděkování

Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Hlavními recenzenty pro tento kurz byli Dave Gardner, Zack Jones, Teresa Murphy a Bernadette Leigh. Chcete si projít moje nadcházející články na WEBU MSDN? Pokud ano, dejte mi čáru na mitchell@4GuysFromRolla.comadresu .