Создание пользовательского поставщика карт сайтов, управляемых базами данных (VB)
Поставщик карты сайта по умолчанию в ASP.NET 2.0 извлекает данные из статического XML-файла. Хотя поставщик на основе XML подходит для многих небольших и средних веб-сайтов, для больших веб-приложений требуется более динамическая карта сайта. В этом руководстве мы создадим настраиваемый поставщик карты сайта, который извлекает данные из уровня бизнес-логики, который, в свою очередь, извлекает данные из базы данных.
Введение
функция карты сайта ASP.NET 2.0 позволяет разработчику страниц определять карту сайта веб-приложения в некоторой постоянной среде, например в XML-файле. После определения данные карты сайта можно получить программным способом через SiteMap
класс в System.Web
пространстве имен или с помощью различных элементов управления навигацией, таких как элементы управления SiteMapPath, Menu и TreeView. Система карты сайта использует модель поставщика, чтобы различные реализации сериализации карты сайта могли создаваться и подключаться к веб-приложению. Поставщик карты сайта по умолчанию, который поставляется с ASP.NET 2.0, сохраняет структуру карты сайта в XML-файле. Еще в руководстве по эталонным страницам и навигации по сайтам мы создали файл с именем Web.sitemap
, который содержал эту структуру и обновлял XML с каждым новым разделом учебника.
Поставщик карты сайта на основе XML по умолчанию хорошо работает, если структура карты сайта довольно статичная, например для этих руководств. Однако во многих сценариях требуется более динамическая карта сайта. Рассмотрим карту сайта, показанную на рис. 1, где каждая категория и продукт отображаются в виде разделов в структуре веб-сайта. С помощью этой карты сайта посетите веб-страницу, соответствующую корневому узлу, может отобразить список всех категорий, в то время как посещение определенной веб-страницы категории будет выводить список продуктов этой категории и просматривать веб-страницу конкретного продукта, чтобы отобразить сведения о продукте.
Рис. 1. Категории и продукты макияж структуры карты сайта (щелкните, чтобы просмотреть изображение полного размера)
Хотя эта структура на основе категорий и продуктов может быть жестко закодирована в Web.sitemap
файл, файл должен обновляться при каждом добавлении, удалении или переименовании категории или продукта. Следовательно, обслуживание карты сайта значительно упрощается, если его структура была получена из базы данных или, в идеале, из уровня бизнес-логики архитектуры приложения. Таким образом, при добавлении, переименовании или удалении продуктов и категорий карта сайта автоматически обновляется, чтобы отразить эти изменения.
Так как сериализация карты сайта ASP.NET 2.0 создается на вершине модели поставщика, мы можем создать собственный поставщик пользовательской карты сайта, который захватывает свои данные из альтернативного хранилища данных, например базы данных или архитектуры. В этом руководстве мы создадим настраиваемый поставщик, который извлекает данные из BLL. Давайте приступим!
Примечание.
Поставщик пользовательской карты сайта, созданный в этом руководстве, тесно связан с архитектурой приложения и моделью данных. Джефф Prosise s Storing Site Maps in SQL Server и Поставщик карты сайта SQL, которые вы ждали статьи, рассматривают обобщенный подход к хранению данных карты сайта в SQL Server.
Шаг 1. Создание веб-страниц пользовательского поставщика карт сайта
Прежде чем приступить к созданию настраиваемого поставщика карты сайта, сначала добавьте страницы ASP.NET, необходимые для этого руководства. Сначала добавьте новую папку с именем SiteMapProvider
. Затем добавьте в нее следующие ASP.NET страницы, чтобы связать каждую страницу с главной страницей Site.master
:
Default.aspx
ProductsByCategory.aspx
ProductDetails.aspx
Кроме того, добавьте в папку вложенную CustomProviders
папку App_Code
.
Рис. 2. Добавление страниц ASP.NET для учебников, связанных с поставщиком карт сайта
Так как в этом разделе есть только одно руководство, нам не нужно Default.aspx
перечислять учебники раздела. Вместо этого Default.aspx
будут отображаться категории в элементе управления GridView. Мы будем решать эту проблему на шаге 2.
Затем обновите Web.sitemap
ссылку на страницу Default.aspx
. В частности, добавьте следующую разметку после кэширования <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." />
После обновления Web.sitemap
просмотрите веб-сайт учебников через браузер. Меню слева теперь содержит элемент для руководства по поставщику карты сайта.
Рис. 3. Схема сайта теперь включает запись для руководства по поставщику карт сайта
В этом руководстве основное внимание уделяется созданию пользовательского поставщика карты сайта и настройке веб-приложения для использования этого поставщика. В частности, мы создадим поставщика, который возвращает карту сайта, которая включает корневой узел вместе с узлом для каждой категории и продукта, как показано на рис. 1. Как правило, каждый узел на карте сайта может указывать URL-адрес. Для карты сайта будет url-адрес ~/SiteMapProvider/Default.aspx
корневого узла, который будет перечислять все категории в базе данных. Каждый узел категории на карте сайта будет иметь URL-адрес, указывающий на ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID
, который будет перечислять все продукты в указанном идентификаторе категории. Наконец, каждый узел карты сайта продукта будет указывать на ~/SiteMapProvider/ProductDetails.aspx?ProductID=productID
, на который будут отображаться сведения о конкретном продукте.
Чтобы начать, необходимо создать Default.aspx
страницы и ProductDetails.aspx
страницыProductsByCategory.aspx
. Эти страницы выполняются в шагах 2, 3 и 4 соответственно. Так как в этом руководстве содержатся сведения о поставщиках карт сайта, и с тех пор, как прошлые учебники рассмотрели создание таких многостраничных эталонных и подробных отчетов, мы спешим по шагам 2–4. Если вам требуется обновление при создании главных и подробных отчетов, охватывающих несколько страниц, обратитесь к руководству по фильтрации основных и подробных сведений по двум страницам .
Шаг 2. Отображение списка категорий
Default.aspx
Откройте страницу в SiteMapProvider
папке и перетащите GridView из панели элементов в конструктор, установив для нее значение ID
Categories
. Из смарт-тега GridView привязать его к новому объекту ObjectDataSource с именем CategoriesDataSource
и настроить его таким образом, чтобы он извлекал данные с помощью CategoriesBLL
метода класса GetCategories
. Так как в этом GridView отображаются только категории и не предоставляются возможности изменения данных, задайте раскрывающийся список на вкладках UPDATE, INSERT и DELETE (Нет).
Рис. 4. Настройка ObjectDataSource для возврата категорий с помощью GetCategories
метода (щелкните, чтобы просмотреть изображение полного размера)
Рис. 5. Задайте раскрывающийся список в вкладках UPDATE, INSERT и DELETE (Нет) (Щелкните, чтобы просмотреть изображение полного размера)
После завершения работы мастера настройки источника данных Visual Studio добавит BoundField для CategoryID
, CategoryName
и Description
NumberOfProducts
.BrochurePath
Измените GridView таким образом, чтобы он содержал CategoryName
Description
только свойства BoundFields и обновлял CategoryName
свойство BoundField HeaderText
на "Категория".
Затем добавьте HyperLinkField и поместите его таким образом, чтобы оно было левым. Задайте для свойства DataNavigateUrlFields
значение CategoryID
, а для свойства DataNavigateUrlFormatString
— значение ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}
. Text
Задайте для свойства значение View Products.
Рис. 6. Добавление HyperLinkField в Categories
GridView
После создания ObjectDataSource и настройки полей GridView два элемента управления декларативной разметки будут выглядеть следующим образом:
<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>
На рисунке 7 показано Default.aspx
, когда просматривается браузер. Щелкнув ссылку ProductsByCategory.aspx?CategoryID=categoryID
"Просмотр продуктов" категории, мы создадим ее на шаге 3.
Рис. 7. Каждая категория указана вместе со ссылкой "Просмотр продуктов" (щелкните, чтобы просмотреть изображение полного размера)
Шаг 3. Перечисление продуктов выбранной категории
Откройте страницу ProductsByCategory.aspx
и добавьте GridView, назвав ее ProductsByCategory
. Из смарт-тега привязать GridView к новому объекту ObjectDataSource с именем ProductsByCategoryDataSource
. Настройте ObjectDataSource для использования ProductsBLL
метода класса GetProductsByCategoryID(categoryID)
и задайте раскрывающимся спискам значение (None) на вкладках UPDATE, INSERT и DELETE.
Рис. 8. Использование ProductsBLL
метода класса GetProductsByCategoryID(categoryID)
(щелкните, чтобы просмотреть изображение полного размера)
Последний шаг мастера настройки источника данных запрашивает источник параметров для categoryID. Так как эти сведения передаются через поле CategoryID
запроса, выберите QueryString из раскрывающегося списка и введите CategoryID в текстовое поле QueryStringField, как показано на рис. 9. Чтобы завершить работу мастера, нажмите кнопку Готово .
Рис. 9. Используйте CategoryID
поле querystring для параметра categoryID (щелкните, чтобы просмотреть изображение полного размера)
После завершения работы мастера Visual Studio добавит соответствующие boundFields и CheckBoxField в GridView для полей данных продукта. Удалите все, кроме ProductName
, UnitPrice
и SupplierName
BoundFields. Настройте эти три свойства BoundFields HeaderText
для чтения Product, Price и Supplier соответственно. Форматирование UnitPrice
BoundField в виде валюты.
Затем добавьте HyperLinkField и переместите его в левую позицию. Присвойте свойству Text
значение View Details, свойству ProductID
DataNavigateUrlFields
и свойству ~/SiteMapProvider/ProductDetails.aspx?ProductID={0}
DataNavigateUrlFormatString
.
Рис. 10. Добавление hyperLinkField сведений о представлении, на которое указывает ProductDetails.aspx
После выполнения этих настроек декларативная разметка GridView и ObjectDataSource должны выглядеть следующим образом:
<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>
Вернитесь к просмотру Default.aspx
через браузер и щелкните ссылку "Просмотр продуктов" для напитков. При этом вы ProductsByCategory.aspx?CategoryID=1
увидите имена, цены и поставщики продуктов в базе данных Northwind, принадлежащих категории "Напитки" (см. рис. 11). Вы можете дополнительно улучшить эту страницу, чтобы включить ссылку для возврата пользователей на страницу описания категорий (Default.aspx
) и элемент управления DetailsView или FormView, отображающий имя и описание выбранной категории.
Рис. 11. Отображаются имена напитков, цены и поставщики (щелкните, чтобы просмотреть изображение полного размера)
Шаг 4. Отображение сведений о продукте
Последняя страница ProductDetails.aspx
отображает выбранные сведения о продуктах. Откройте ProductDetails.aspx
и перетащите DetailsView из панели элементов в конструктор. Задайте для свойства ProductInfo
DetailsView ID
значение и удалите его Height
и Width
значения свойств. Из смарт-тега привязать DetailsView к новому объекту ObjectDataSource с именем ProductDataSource
, настроив ObjectDataSource для извлечения данных из ProductsBLL
метода класса GetProductByProductID(productID)
. Как и в случае с предыдущими веб-страницами, созданными на шагах 2 и 3, установите раскрывающийся список на вкладках UPDATE, INSERT и DELETE (Нет).
Рис. 12. Настройка ObjectDataSource для использования GetProductByProductID(productID)
метода (щелкните, чтобы просмотреть изображение полного размера)
Последний шаг мастера настройки источника данных запрашивает источник параметра productID . Так как эти данные передаются через поле ProductID
строки запросов, задайте раскрывающийся список для QueryString и текстового поля QueryStringField значение ProductID. Наконец, нажмите кнопку "Готово", чтобы завершить работу мастера.
Рис. 13. Настройка параметра productID для извлечения значения из ProductID
поля запроса (щелкните, чтобы просмотреть изображение полного размера)
После завершения работы мастера настройки источника данных Visual Studio создаст соответствующие boundFields и CheckBoxField в DetailsView для полей данных продукта. ProductID
Удалите поля , SupplierID
и CategoryID
BoundFields и настройте остальные поля, как вы видите. После нескольких эстетических конфигураций моей декларативной разметки DetailsView и ObjectDataSource выглядели следующим образом:
<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>
Чтобы проверить эту страницу, вернитесь к Default.aspx
категории "Просмотр продуктов" и нажмите кнопку "Просмотреть продукты". В списке продуктов для напитков щелкните ссылку "Просмотр сведений" для Чаи Чай. Это приведет вас к ProductDetails.aspx?ProductID=1
просмотру, в котором показаны подробности чаи чая (см. рисунок 14).
Рис. 14. Поставщик чаи чая, категория, цена и другие сведения отображаются (щелкните, чтобы просмотреть изображение полного размера)
Шаг 5. Общие сведения о внутренней работе поставщика карты сайта
Карта сайта представлена в памяти веб-сервера в виде коллекции SiteMapNode
экземпляров, которые образуют иерархию. Должно быть ровно один корень, все не корневые узлы должны иметь ровно один родительский узел, а все узлы могут иметь произвольное число дочерних узлов. Каждый объект представляет раздел в структуре веб-сайта. Эти SiteMapNode
разделы обычно имеют соответствующую веб-страницу. Следовательно, класс имеет такие свойства, SiteMapNode
как Title
, Url
и Description
, которые предоставляют сведения для разделаSiteMapNode
, который представляет. Существует также Key
свойство, которое однозначно идентифицирует каждую SiteMapNode
из иерархий, а также свойства, используемые для установления этой иерархииChildNodes
, , ParentNode
и NextSibling
PreviousSibling
т. д.
На рисунке 15 показана общая структура карты сайта на рис. 1, но с подробными сведениями о реализации.
Рис. 15. У каждого SiteMapNode
есть свойства, например Title
, Url
Key
и т. д. (Щелкните, чтобы просмотреть изображение полного размера)
Карта сайта доступна через SiteMap
класс в System.Web
пространстве имен. Это свойство класса RootNode
возвращает корневой SiteMapNode
экземпляр карты сайта; CurrentNode
возвращает SiteMapNode
свойство, свойство которого Url
соответствует URL-адресу текущей запрошенной страницы. Этот класс используется внутренне ASP.NET веб-элементами управления навигации 2.0.
SiteMap
При доступе к свойствам класса он должен сериализовать структуру карты сайта из некоторой постоянной среды в память. Однако логика сериализации карты сайта не жестко закодирована в SiteMap
класс. Вместо этого во время выполнения SiteMap
класс определяет, какой поставщик карты сайта будет использоваться для сериализации. По умолчанию XmlSiteMapProvider
используется класс , который считывает структуру карты сайта из правильно отформатированного XML-файла. Однако с небольшой работой мы можем создать собственный собственный поставщик карты сайта.
Все поставщики карт сайта должны быть производными от SiteMapProvider
класса, который включает в себя основные методы и свойства, необходимые для поставщиков карт сайта, но пропускает многие сведения о реализации. Второй класс расширяет StaticSiteMapProvider
SiteMapProvider
класс и содержит более надежную реализацию необходимых функций. Внутри системы хранятся экземпляры карты сайта и Hashtable
предоставляются такие методы, Clear()
RemoveNode(siteMapNode),
как AddNode(child, parent)
добавление и удаление SiteMapNode
s во внутреннийHashtable
.StaticSiteMapProvider
SiteMapNode
Класс XmlSiteMapProvider
является производным от StaticSiteMapProvider
.
При создании пользовательского поставщика карты сайта, расширяющегося StaticSiteMapProvider
, существует два абстрактных метода, которые необходимо переопределить: BuildSiteMap
и GetRootNodeCore
. BuildSiteMap
Как подразумевает его имя, отвечает за загрузку структуры карты сайта из постоянного хранилища и создания ее в памяти. GetRootNodeCore
возвращает корневой узел на карте сайта.
Прежде чем веб-приложение сможет использовать поставщик карты сайта, его необходимо зарегистрировать в конфигурации приложения. По умолчанию XmlSiteMapProvider
класс регистрируется с помощью имени AspNetXmlSiteMapProvider
. Чтобы зарегистрировать дополнительных поставщиков карт сайта, добавьте следующую разметку Web.config
в:
<configuration>
<system.web>
...
<siteMap defaultProvider="defaultProviderName">
<providers>
<add name="name" type="type" />
</providers>
</siteMap>
</system.web>
</configuration>
Значение имени присваивает поставщику удобочитаемое пользователем имя, а тип задает полное имя типа поставщика карты сайта. Мы рассмотрим конкретные значения для значений имен и типов в шаге 7 после создания пользовательского поставщика карты сайта.
Класс поставщика карты сайта создается при первом доступе из SiteMap
класса и остается в памяти в течение всего времени существования веб-приложения. Так как существует только один экземпляр поставщика карты сайта, который может вызываться из нескольких одновременных посетителей веб-сайта, крайне важно, чтобы методы поставщика были потокобезопасны.
Для повышения производительности и масштабируемости важно кэшировать структуру карты сайта в памяти и возвращать эту кэшированную структуру, а не повторно использовать ее при BuildSiteMap
каждом вызове метода. BuildSiteMap
может вызываться несколько раз на запрос страницы для каждого пользователя в зависимости от элементов управления навигацией, используемых на странице, и глубины структуры карты сайта. В любом случае, если мы не кэшируем структуру карты сайта при BuildSiteMap
каждом вызове, нам потребуется повторно получить сведения о продукте и категории из архитектуры (что приведет к запросу к базе данных). Как мы обсуждали в предыдущих руководствах по кэшированию, кэшированные данные могут стать устаревшими. Для борьбы с этим можно использовать срок действия зависимостей на основе зависимостей кэша SQL или времени.
Примечание.
Поставщик карты сайта может при необходимости переопределить Initialize
метод. Initialize
вызывается при первом создании экземпляра поставщика карты сайта и передается все пользовательские атрибуты, назначенные поставщику в Web.config
элементе<add>
, например: <add name="name" type="type" customAttribute="value" />
Полезно, если вы хотите разрешить разработчику страницы указывать различные параметры, связанные с поставщиком карты сайта, не изменяя код поставщика. Например, если мы считывали данные категории и продуктов непосредственно из базы данных в отличие от архитектуры, мы, скорее всего, хотим разрешить разработчику страницы указывать базу данных строка подключения, Web.config
а не использовать жестко закодированное значение в коде поставщика. Настраиваемый поставщик карты сайта, который мы создадим на шаге 6, не переопределяет этот Initialize
метод. Пример использования метода см. в статье jeff Prosise в службе "Хранение карт сайтов" в SQL Server.Initialize
Шаг 6. Создание пользовательского поставщика карты сайта
Чтобы создать настраиваемый поставщик карты сайта, который создает карту сайта из категорий и продуктов в базе данных Northwind, необходимо создать класс, расширяющийся StaticSiteMapProvider
. На шаге 1 я попросил добавить CustomProviders
папку в App_Code
папку — добавьте новый класс в эту папку с именем NorthwindSiteMapProvider
. Добавьте в класс NorthwindSiteMapProvider
следующий код.
Imports System.Web
Imports System.Web.Caching
Public Class NorthwindSiteMapProvider
Inherits StaticSiteMapProvider
Private ReadOnly siteMapLock As New Object()
Private root As SiteMapNode = Nothing
Public Const CacheDependencyKey As String = "NorthwindSiteMapProviderCacheDependency"
Public Overrides Function BuildSiteMap() As System.Web.SiteMapNode
' Use a lock to make this method thread-safe
SyncLock siteMapLock
' First, see if we already have constructed the
' rootNode. If so, return it...
If root IsNot Nothing Then
Return root
End If
' We need to build the site map!
' Clear out the current site map structure
MyBase.Clear()
' Get the categories and products information from the database
Dim productsAPI As New ProductsBLL()
Dim products As Northwind.ProductsDataTable = productsAPI.GetProducts()
' Create the root SiteMapNode
root = New SiteMapNode( _
Me, "root", "~/SiteMapProvider/Default.aspx", "All Categories")
AddNode(root)
' Create SiteMapNodes for the categories and products
For Each product As Northwind.ProductsRow In products
' Add a new category SiteMapNode, if needed
Dim categoryKey, categoryName As String
Dim createUrlForCategoryNode As Boolean = True
If product.IsCategoryIDNull() Then
categoryKey = "Category:None"
categoryName = "None"
createUrlForCategoryNode = False
Else
categoryKey = String.Concat("Category:", product.CategoryID)
categoryName = product.CategoryName
End If
Dim categoryNode As SiteMapNode = FindSiteMapNodeFromKey(categoryKey)
' Add the category SiteMapNode if it does not exist
If categoryNode Is Nothing Then
Dim productsByCategoryUrl As String = String.Empty
If createUrlForCategoryNode Then
productsByCategoryUrl = _
"~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=" & _
product.CategoryID
End If
categoryNode = New SiteMapNode _
(Me, categoryKey, productsByCategoryUrl, categoryName)
AddNode(categoryNode, root)
End If
' Add the product SiteMapNode
Dim productUrl As String = _
"~/SiteMapProvider/ProductDetails.aspx?ProductID=" & _
product.ProductID
Dim productNode As New SiteMapNode _
(Me, String.Concat("Product:", product.ProductID), _
productUrl, product.ProductName)
AddNode(productNode, categoryNode)
Next
' Add a "dummy" item to the cache using a SqlCacheDependency
' on the Products and Categories tables
Dim productsTableDependency As New _
System.Web.Caching.SqlCacheDependency("NorthwindDB", "Products")
Dim categoriesTableDependency As New _
System.Web.Caching.SqlCacheDependency("NorthwindDB", "Categories")
' Create an AggregateCacheDependency
Dim aggregateDependencies As 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, AddressOf OnSiteMapChanged)
' Finally, return the root node
Return root
End SyncLock
End Function
Protected Overrides Function GetRootNodeCore() As System.Web.SiteMapNode
Return BuildSiteMap()
End Function
Protected Sub OnSiteMapChanged _
(key As String, value As Object, reason As CacheItemRemovedReason)
SyncLock siteMapLock
If String.Compare(key, CacheDependencyKey) = 0 Then
' Refresh the site map
root = Nothing
End If
End SyncLock
End Sub
Public ReadOnly Property CachedDate() As Nullable(Of DateTime)
Get
Dim value As Object = HttpRuntime.Cache(CacheDependencyKey)
If value Is Nothing OrElse Not TypeOf value Is Nullable(Of DateTime) Then
Return Nothing
Else
Return CType(value, Nullable(Of DateTime))
End If
End Get
End Property
End Class
Начнем с изучения этого метода классаBuildSiteMap
, который начинается с инструкцииlock
. Оператор lock
позволяет одновременно вводить только один поток, тем самым сериализуя доступ к коду и предотвращая переход на два параллельных потока друг на друга.
Переменная root
уровня SiteMapNode
класса используется для кэширования структуры карты сайта. Когда карта сайта создается в первый раз или в первый раз после изменения базовых данных, root
будет Nothing
создана структура карты сайта. Корневой узел карты сайта назначается root
во время процесса построения, root
чтобы при следующем вызове этого метода не было Nothing
. Следовательно, до тех пор, пока root
структура карты сайта не Nothing
будет возвращена вызывающему объекту без необходимости повторно создать его.
Если корневой каталог Nothing
, структура карты сайта создается из сведений о продукте и категории. Карта сайта создается путем создания SiteMapNode
экземпляров, а затем формирования иерархии с помощью вызовов StaticSiteMapProvider
метода класса AddNode
. AddNode
выполняет внутреннюю бухгалтерию, сохраняя в ней Hashtable
экземпляры assortedSiteMapNode
. Прежде чем приступить к созданию иерархии, мы начнем с вызова Clear
метода, который очищает элементы из внутреннего Hashtable
. ProductsBLL
Затем метод класса GetProducts
и результирующий ProductsDataTable
результат хранятся в локальных переменных.
Построение карты сайта начинается с создания корневого узла и назначения его root
. Перегрузка конструктора s, используемого SiteMapNode
здесь, и во всем этом BuildSiteMap
передается следующая информация:
- Ссылка на поставщика карты сайта (
Me
). Key
SSiteMapNode
. Это необходимое значение должно быть уникальным для каждогоSiteMapNode
.Url
SSiteMapNode
.Url
является необязательным, но если указано, каждоеSiteMapNode
Url
значение должно быть уникальным.- Значение
SiteMapNode
sTitle
, которое является обязательным.
Вызов AddNode(root)
метода добавляет SiteMapNode
root
карту сайта в качестве корневого элемента. Далее перечисляется каждый ProductRow
из них ProductsDataTable
. Если для текущей SiteMapNode
категории продукта уже существует, она ссылается. В противном случае создается новая SiteMapNode
для категории и добавляется в качестве дочернего элемента SiteMapNode``root
вызова AddNode(categoryNode, root)
метода. После того как соответствующий узел категории SiteMapNode
найден или создан, SiteMapNode
создается для текущего продукта и добавляется в качестве дочернего элемента категории SiteMapNode
через AddNode(productNode, categoryNode)
. Обратите внимание, что значение свойства категории SiteMapNode
Url
находится ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID
во время назначения ~/SiteMapNode/ProductDetails.aspx?ProductID=productID
свойства продукта SiteMapNode
Url
.
Примечание.
Эти продукты, имеющие значение базы данных NULL
для них CategoryID
, группируются под категорией SiteMapNode
, свойство которой Title
имеет значение None и свойство которого Url
задано как пустая строка. Я решил задать Url
пустую строку, так как ProductBLL
метод класса GetProductsByCategory(categoryID)
в настоящее время не имеет возможности возвращать только те продукты со значением NULL
CategoryID
. Кроме того, я хотел продемонстрировать, как элементы управления навигацией отображают значение SiteMapNode
, которое не имеет значения для его Url
свойства. Я призываю вас расширить это руководство, чтобы свойство None SiteMapNode
Url
указывает на ProductsByCategory.aspx
, но отображает только продукты со значениями NULL
CategoryID
.
После создания карты сайта произвольный объект добавляется в кэш данных с помощью зависимости кэша SQL от Categories
объектов и Products
таблиц.AggregateCacheDependency
Мы изучили использование зависимостей кэша SQL в предыдущем руководстве с помощью зависимостей кэша SQL. Однако поставщик пользовательской карты сайта использует перегрузку метода кэша Insert
данных, который мы еще не изучили. Эта перегрузка принимает в качестве конечного входного параметра делегат, вызываемый при удалении объекта из кэша. В частности, мы передаем новый CacheItemRemovedCallback
делегат , указывающий на OnSiteMapChanged
метод, определенный далее в NorthwindSiteMapProvider
классе.
Примечание.
Представление карты сайта в памяти кэшируется с помощью переменной root
уровня класса. Так как существует только один экземпляр класса поставщика пользовательской карты сайта и так как этот экземпляр является общим для всех потоков в веб-приложении, эта переменная класса служит кэшем. Метод BuildSiteMap
также использует кэш данных, но только в качестве средства для получения уведомлений при изменении базовых данных базы данных в Categories
таблицах или Products
таблицах. Обратите внимание, что значение, введенное в кэш данных, — это только текущая дата и время. Фактические данные карты сайта не помещают в кэш данных.
Метод BuildSiteMap
завершается путем возврата корневого узла карты сайта.
Остальные методы довольно просты. GetRootNodeCore
отвечает за возврат корневого узла. Так как BuildSiteMap
возвращает корневой каталог, GetRootNodeCore
просто возвращает BuildSiteMap
возвращаемое значение. Метод OnSiteMapChanged
возвращает root
значение Nothing
, когда элемент кэша удаляется. При следующем Nothing
BuildSiteMap
вызове корневого набора структура карты сайта будет перестроена. Наконец, CachedDate
свойство возвращает значение даты и времени, хранящееся в кэше данных, если такое значение существует. Это свойство можно использовать разработчиком страницы для определения времени последнего кэширования данных карты сайта.
Шаг 7. РегистрацияNorthwindSiteMapProvider
Чтобы веб-приложение использовало поставщика карты сайта, созданного NorthwindSiteMapProvider
на шаге 6, необходимо зарегистрировать его в <siteMap>
разделе Web.config
. В частности, добавьте в элемент следующую разметку<system.web>
:Web.config
<siteMap defaultProvider="AspNetXmlSiteMapProvider">
<providers>
<add name="Northwind" type="NorthwindSiteMapProvider" />
</providers>
</siteMap>
Эта разметка выполняет две действия: во-первых, она указывает, что встроенный AspNetXmlSiteMapProvider
поставщик карты сайта по умолчанию; во-вторых, он регистрирует настраиваемый поставщик карты сайта, созданный на шаге 6 с понятным для человека именем Northwind.
Примечание.
Для поставщиков карт сайта, расположенных в папке приложения App_Code
, значение type
атрибута — это просто имя класса. Кроме того, поставщик пользовательской карты сайта мог быть создан в отдельном проекте библиотеки классов с скомпилированной сборкой, размещенной в каталоге веб-приложения /Bin
. В этом случае значение атрибута type
будет пространством имен.ClassName, AssemblyName .
После обновления Web.config
просмотрите любую страницу из учебников в браузере. Обратите внимание, что интерфейс навигации слева по-прежнему отображает разделы и руководства, определенные в Web.sitemap
. Это связано с тем, что мы оставили AspNetXmlSiteMapProvider
в качестве поставщика по умолчанию. Чтобы создать элемент пользовательского интерфейса навигации, использующий этот NorthwindSiteMapProvider
интерфейс, необходимо явно указать, что поставщик карты сайта Northwind должен использоваться. Мы посмотрим, как это сделать на шаге 8.
Шаг 8. Отображение сведений о карте сайта с помощью пользовательского поставщика карты сайта
С помощью пользовательского поставщика карты сайта, созданного и зарегистрированногоWeb.config
, мы готовы добавить элементы управления навигацией в Default.aspx
ProductsByCategory.aspx
папку и ProductDetails.aspx
страницы.SiteMapProvider
Начните с открытия Default.aspx
страницы и перетащите ее SiteMapPath
из панели элементов в конструктор. Элемент управления SiteMapPath находится в разделе навигации панели элементов.
Рис. 16. Добавление SiteMapPath в Default.aspx
(щелкните, чтобы просмотреть изображение полного размера)
В элементе управления SiteMapPath отображается панель навигации, указывающая расположение текущей страницы на карте сайта. Мы добавили SiteMapPath в верхнюю часть главной страницы в руководстве по эталонным страницам и навигации по сайтам.
Просмотрите эту страницу через браузер. SiteMapPath, добавленный на рис. 16, использует поставщик карты сайта по умолчанию, извлекая данные из Web.sitemap
. Таким образом, в области навигации показано > , как главная настройка карты сайта, как в правом верхнем углу.
Рис. 17. Хлебная диаграмма использует поставщика карты сайта по умолчанию (щелкните, чтобы просмотреть изображение полного размера)
Чтобы добавить SiteMapPath на рис. 16, используйте настраиваемый поставщик карты сайта, созданный на шаге 6, задайте для свойства SiteMapProvider
Northwind имя, которое мы назначили NorthwindSiteMapProvider
в Web.config
. К сожалению, конструктор продолжает использовать поставщика карты сайта по умолчанию, но если вы посещаете страницу через браузер после изменения этого свойства, вы увидите, что хлебоборец теперь использует настраиваемый поставщик карты сайта.
Рис. 18. Теперь хлебограмма использует поставщика NorthwindSiteMapProvider
пользовательской карты сайта (щелкните, чтобы просмотреть изображение полного размера)
Элемент управления SiteMapPath отображает более функциональный пользовательский интерфейс на ProductsByCategory.aspx
страницах и ProductDetails.aspx
страницах. Добавьте SiteMapPath на эти страницы, задав SiteMapProvider
свойство как в Northwind. Щелкните Default.aspx
ссылку "Просмотр продуктов" для напитков, а затем на ссылке "Сведения о просмотре" для чая чая. Как показано на рисунке 19, хлебная диаграмма включает в себя текущий раздел карты сайта (Чай Чаи) и его предки: напитки и все категории.
Рис. 19. Теперь хлебограмма использует поставщика NorthwindSiteMapProvider
пользовательской карты сайта (щелкните, чтобы просмотреть изображение полного размера)
Другие элементы пользовательского интерфейса навигации можно использовать в дополнение к SiteMapPath, таким как элементы управления Menu и TreeView. ProductsByCategory.aspx
ProductDetails.aspx
Страницы Default.aspx
и страницы в скачиваемом руководстве, например все элементы управления меню (см. рис. 20). Дополнительные сведения об элементах управления навигации и системе карт сайта в ASP.NET ASP.NET 2.0 см. в разделе ASP.NET 2.0 в разделе "Сложные функции навигации" и "Использование элементов управления навигацией" в ASP.NET 2.0.
Рис. 20. Список элементов управления меню "Каждая из категорий и продуктов" (щелкните, чтобы просмотреть изображение полного размера)
Как упоминалось ранее в этом руководстве, структура карты сайта может быть доступ к ней программным способом SiteMap
с помощью класса. Следующий код возвращает корневой каталог SiteMapNode
поставщика по умолчанию:
Dim root As SiteMapNode = SiteMap.RootNode
AspNetXmlSiteMapProvider
Так как поставщик по умолчанию для нашего приложения, приведенный выше код вернет корневой узел, определенный вWeb.sitemap
. Чтобы ссылаться на поставщика карты сайта, отличного от используемого по умолчанию, используйте SiteMap
свойство классаProviders
, как показано ниже.
Dim root As SiteMapNode = SiteMap.Providers("name").RootNode
Где имя — имя пользовательского поставщика карты сайта (Northwind, для нашего веб-приложения).
Для доступа к члену, конкретному поставщику карты сайта, используйте SiteMap.Providers["name"]
для получения экземпляра поставщика, а затем приведения его к соответствующему типу. Например, чтобы отобразить NorthwindSiteMapProvider
свойство s CachedDate
на странице ASP.NET, используйте следующий код:
Dim customProvider As NorthwindSiteMapProvider = _
TryCast(SiteMap.Providers("Northwind"), NorthwindSiteMapProvider)
If customProvider IsNot Nothing Then
Dim lastCachedDate As Nullable(Of DateTime) = customProvider.CachedDate
If lastCachedDate.HasValue Then
SiteMapLastCachedDate.Text = _
"Site map cached on: " & lastCachedDate.Value.ToString()
Else
SiteMapLastCachedDate.Text = "The site map is being reconstructed!"
End If
End If
Примечание.
Обязательно протестируйте функцию зависимостей кэша SQL. После посещения Default.aspx
ProductsByCategory.aspx
страниц и ProductDetails.aspx
страниц перейдите к одному из учебников в разделе "Редактирование, вставка и удаление" и измените имя категории или продукта. Затем вернитесь к одной из страниц в папке SiteMapProvider
. Если достаточно времени прошло для механизма опроса, чтобы отметить изменение базовой базы данных, карта сайта должна быть обновлена, чтобы отобразить новое имя продукта или категории.
Итоги
ASP.NET 2.0 функции карты сайта включают SiteMap
класс, ряд встроенных веб-элементов управления навигацией и поставщик карты сайта по умолчанию, который ожидает, что сведения карты сайта сохраняются в XML-файле. Чтобы использовать сведения карты сайта из другого источника, например из базы данных, архитектуры приложения или удаленной веб-службы, необходимо создать настраиваемый поставщик карты сайта. Это предполагает создание класса, который является производным от класса напрямую или косвенно SiteMapProvider
.
В этом руководстве мы узнали, как создать настраиваемый поставщик карты сайта, основанный на карте сайта на основе сведений о продукте и категории, отбрасированных из архитектуры приложения. Наш поставщик расширил StaticSiteMapProvider
класс и повлечет за собой создание BuildSiteMap
метода, который извлекал данные, создал иерархию карты сайта и кэшировал полученную структуру в переменной уровня класса. Мы использовали зависимость кэша SQL с функцией обратного вызова, чтобы недействительным кэшируемую структуру при изменении базового Categories
или Products
данных.
Счастливое программирование!
Дополнительные материалы
Дополнительные сведения о разделах, описанных в этом руководстве, см. в следующих ресурсах:
- Хранение карт сайтов в SQL Server и поставщике карт сайта SQL, который вы ждали
- Набор средств поставщика
- ASP.NET 2.0 сложные функции навигации по сайту
Об авторе
Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Сэмс Учит себя ASP.NET 2.0 в 24 часах. Он может быть достигнут в mitchell@4GuysFromRolla.com. или через его блог, который можно найти на http://ScottOnWriting.NET.
Особое спасибо
Эта серия учебников была проверена многими полезными рецензентами. Ведущие рецензенты для этого руководства были Дэйв Гарднер, Зак Джонс, Тереса Мерфи и Бернадетт Ли. Хотите просмотреть мои предстоящие статьи MSDN? Если да, упадите меня линию в mitchell@4GuysFromRolla.com.