(0) exportieren Drucken
Alle erweitern
Erweitern Minimieren

Ein SQL-SiteMapProvider für SQL Server und ASP.NET 2.0

Veröffentlicht: 30. Mrz 2006

Von Jeff Prosise

Laden Sie den Code zu diesem Artikel herunter: WickedCode0602.exe (117KB)

Auf dieser Seite

Der neue und verbesserte SQL-SiteMapProvider
Verwenden von SqlSiteMapProvider
Erstellen der Sitemap-Datenbank
Der Autor

Nachdem ASP.NET 2.0 nun erhältlich ist, scheint es angebracht zu sein, sich nochmals mit einem Feature zu befassen, das ganz oben auf der Wunschliste vieler Entwickler steht: ein SQL Server-SiteMapProvider.

Wie Sie vielleicht wissen, wird das Erstellen datengesteuerter Sitenavigationsoberflächen durch ASP.NET 2.0 erheblich vereinfacht. Sie erstellen eine Sitemap, platzieren ein SiteMapDataSource-Steuerelement auf der Seite und binden ein Menu- oder TreeView-Steuerelement an SiteMapDataSource. SiteMapDataSource verwendet den standardmäßigen SiteMapProvider (typischerweise XmlSiteMapProvider) zum Lesen der Sitemap und übergibt dann die Sitemap-Knoten an ein Menu oder TreeView, sodass die Knoten in HTML dargestellt werden. Darüber hinaus können Sie der Seite ein SiteMapPath-Steuerelement hinzufügen. SiteMapPath zeigt das bekannte Breadcumb-Steuerelement mit dem Pfad zur aktuellen Seite an. In Abbildung 1 werden die Komponenten des Sitenavigationssubsystems und deren Beziehungen untereinander dargestellt.

Komponenten des Sitenavigationssubsystems und deren Beziehungen untereinander
Abbildung 1: Komponenten des Sitenavigationssubsystems und deren Beziehungen untereinander

Der einzige Nachteil der Sitenavigation ist, dass XmlSiteMapProvider der einzige SiteMapProvider ist, der mit ASP.NET 2.0 bereitgestellt wird. Aus diesem Grund müssen Sitemaps in XML-Dateien gespeichert werden. Bereits vor der Bereitstellung von ASP.NET 2.0 wünschten sich Entwickler eine Möglichkeit, Sitemaps in Datenbanken zu speichern.

In der Wicked Code-Ausgabe vom Juni 2005 wurde eine Lösung in Form eines benutzerdefinierten SiteMapProviders namens SqlSiteMapProvider vorgestellt. Im Gegensatz zu XmlSiteMapProvider liest SqlSiteMapProvider Sitemaps aus SQL Server-Datenbanken. Außerdem wird er mithilfe der ASP.NET 2.0-Provider-Architektur nahtlos im Navigations-Subsystem integriert. Erstellen Sie einfach die Sitemap-Datenbank und registrieren Sie SqlSiteMapProvider als Standardprovider, und alles weitere funktioniert ganz von selbst.

Warum also möchte ich mit diesem Artikel ein Thema ansprechen, das bereits behandelt wurde? Hierfür gibt es drei Gründe: Zunächst einmal habe ich den ganzen Sommer über die meiste Zeit damit verbracht, mich mit der Provider-Architektur zu befassen. Dabei habe ich festgestellt, dass ein paar Verbesserungen der ursprünglichen SqlSiteMapProvider-Implementierung erforderlich sind, um die Konsistenz mit dem integrierten XmlSiteMapProvider zu verbessern. Zweitens wurden an ASP.NET 2.0 zwischen Beta 2 und der endgültigen Version einige umfassende Änderungen vorgenommen, und ich wollte SqlSiteMapProvider für die fertige Plattform aktualisieren. Schließlich – und das ist der wichtigste Grund – wollte ich ein Feature hinzufügen, zu dem mir einige Leser E-Mails geschrieben haben: ein automatisches erneutes Laden der Sitemap nach einer Änderung in der Sitemap-Datenbank. Ohne dieses Feature scheinen viele Leser eine in SQL Server gespeicherte Sitemap für so nützlich zu halten wie ein Flugzeug ohne Flügel. Letzteres musste ich diesen Sommer mit Bedauern untersuchen, als mein ferngesteuertes Lieblingsflugzeug einen Zaunpfahl rammte. Aber diese Geschichte erzähle ich ein anderes Mal.

Der neue und verbesserte SQL-SiteMapProvider

Letztlich erfüllt die neue und verbesserte Version von SqlSiteMapProvider alle meine Anforderungen und leistet noch einiges mehr. Die Architektur ist konsistent mit den integrierten Providern, und sie wird unter ASP.NET 2.0 ausgeführt und kompiliert. Außerdem verwendet sie die SqlCacheDependency-Klasse von ASP.NET 2.0 für die Überwachung der Sitemap-Datenbank und zum Aktualisieren der Sitemap im Falle von Änderungen. XmlSiteMapProvider verfügt über ein ähnliches Feature zum erneuten Laden der Sitemap nach einer Änderung der zugrunde liegenden XML-Sitemapdatei.

In Abbildung 2 wird der Quellcode der neuen Version von SqlSiteMapProvider dargestellt. Die in allen Providern vorhandene Initialize-Methode ist eine spezielle Methode, die von ASP.NET nach dem Laden des Providers aufgerufen wird. ASP.NET übergibt eine Name-Wert-Auflistung namens config an Initialize. Diese Auflistung enthält alle Konfigurationsattribute (und deren Werte), die in dem Konfigurationselement gefunden werden, das den Provider registriert hat. Die Initialize-Methode dient der Anwendung von Konfigurationseinstellungen und der Durchführung aller übrigen Aufgaben, die für die Initialisierung des Providers erforderlich sind. Die Initialize-Methode von SqlSiteMapProvider führt die folgenden Aufgaben durch:

  1. Sie fordert eine SqlClientPermission an, um sicherzustellen, dass sie über die Berechtigungen für den Zugriff auf Datenbanken verfügt. Ohne diese Berechtigungen kann SqlSiteMapProvider nicht ordnungsgemäß funktionieren.

  2. Sie ruft die Initialize-Methode der Basisklasse auf, die unter anderem das securityTrimmingEnabled-Konfigurationsattribut verarbeitet, wenn dieses vorhanden ist.

  3. Sie verarbeitet die Konfigurationsattribute connectionStringName und sqlCacheDependency, sofern diese vorhanden sind.

  4. Sie löst eine Ausnahme aus, wenn das Element, das den Provider registriert, unbekannte Konfigurationsattribute enthält.

Das sqlCacheDependency-Attribut ermöglicht es Ihnen, die SqlSiteMapProvider-Funktion zum Aktualisieren der Sitemap im Falle von Änderungen der zugrunde liegenden Datenbank zu nutzen. Durch Festlegen von sqlCacheDependency auf SiteMapDatabase:SiteMap wird der Provider angewiesen, die Sitemap zu aktualisieren, wenn die Tabelle SiteMap in einer SQL Server 7.0- oder SQL Server 2000-Datenbank geändert wird (SiteMapDatabase gibt durch einen Verweis im Abschnitt <databases> des Konfigurationsabschnitts <sqlCacheDependency> den Datenbanknamen indirekt an). Wenn sich die Sitemap in einer SQL Server 2005-Datenbank befindet, legen Sie sqlCacheDependency stattdessen auf CommandNotification fest. Soweit zunächst als kompakte Zusammenfassung, ausführlichere Informationen finden Sie im Folgenden.

Die Kernkomponente von SqlSiteMapProvider ist die BuildSiteMap-Methode. Diese Methode wird von ASP.NET einige Zeit nach dem Laden des Providers aufgerufen, um die Sitemap zu erstellen. Diese ist einfach eine Auflistung von Sitemap-Knoten, die zu einer Struktur miteinander verknüpft sind. Jeder Sitemap-Knoten ist durch die folgenden Eigenschaften gekennzeichnet: Title gibt den Text an, der in einem Navigationssteuerelement für den Knoten angezeigt wird. Url gibt die URL-Adresse an, zu der gewechselt wird, wenn der Benutzer auf den Knoten klickt. Description gibt einen beschreibenden Text an, der angezeigt wird, wenn der Benutzer den Cursor über dem Knoten platziert. Schließlich gibt Roles die Rolle oder die Rollen an, die zum Anzeigen des Knotens berechtigt sind, wenn Security Trimming aktiviert ist ("*", wenn jeder zur Anzeige berechtigt ist). Mehrere Rollen können mithilfe von Kommas und Semikolons als Trennzeichen angegeben werden.

Die von SqlSiteMapProvider implementierte BuildSiteMap fragt die Sitemap-Datenbank ab. Anschließend werden die Datensätze nacheinander iteriert und in Sitemapknoten umgewandelt. Schließlich wird die Sitemap an ASP.NET übergeben, indem ein Verweis auf den Stamm-Sitemapknoten zurückgegeben wird. Da der Providercode außerhalb der Initialize-Methode threadsicher sein muss, wrappt SqlSiteMapProvider außerdem den gesamten Inhalt von BuildSiteMap in eine Sperranweisung, um gleichzeitige Threadzugriffe zu serialisieren.

BuildSiteMap fragt nicht nur die Datenbank ab und erstellt die Sitemap, sondern auch die grundlegende Infrastruktur, mit der SqlSiteMapProvider die Sitemap aktualisieren kann, wenn die Datenbank geändert wird. Wenn das Konfigurationselement, das den Provider registriert hat, ein sqlCacheDependency="CommandNotification"-Attribut enthält, erstellt BuildSiteMap ein mit SQL Server 2005 kompatibles SqlCacheDependency-Objekt, das den SQL-Befehl zur Abfrage der Sitemap-Datenbank kapselt:

// In Initialize
SqlDependency.Start(_connect);

// In BuildSiteMap
dependency = new SqlCacheDependency(command);

Wenn das Konfigurationselement hingegen den Typ der sqlCacheDependency-Konfigurationszeichenfolge enthält, die in SQL Server 7.0 oder SQL Server 2000 verwendet wird (beispielsweise SiteMapDatabase:SiteMap), erstellt BuildSiteMap ein sqlCacheDependency-Objekt, das den bereitgestellten Datenbank- und Tabellennamen kapselt:

// Initialize
_database = info[0];
_table = info[1];

// BuildSiteMap
dependency = new SqlCacheDependency(_database, _table);

Unabhängig vom erstellten sqlCacheDependency-Typ fügt BuildSiteMap zu einem späteren Zeitpunkt ein triviales Objekt in den ASP.NET-Anwendungscache ein und erstellt eine Abhängigkeit zwischen dem Objekt und der Datenbank, indem sqlCacheDependency im Aufruf von Cache.Insert eingeschlossen wird:

if (dependency != null)
{
    HttpRuntime.Cache.Insert(_cacheDependencyName,
        new object(), dependency,
        Cache.NoAbsoluteExpiration,
        Cache.NoSlidingExpiration,
        CacheItemPriority.NotRemovable,
        new CacheItemRemovedCallback(OnSiteMapChanged));
}

Der letzte Parameter für Cache.Insert weist ASP.NET an, die OnSiteMapChanged-Methode des Providers aufzurufen, wenn sqlCacheDependency eine Cachelöschung auslöst – wenn also die Sitemap-Datenbank geändert wird. OnSiteMapChanged löscht die alte Sitemap und ruft BuildSiteMap auf, um eine neue Sitemap zu erstellen.

Möglicherweise erscheint es Ihnen ungewöhnlich, dass SqlSiteMapProvider den ASP.NET-Anwendungscache verwendet, ohne dort eigentlich Daten zu speichern (schließlich ist das in den Cache eingefügte Objekt einfach ein Marker, der kaum sinnvolle Daten enthält). Jedoch kann SqlSiteMapProvider auf diese Weise von einem Schlüsselfeature von ASP.NET 2.0 profitieren:

ADO.NET 2.0 verfügt über eine SqlDependency-Klasse, mit der Anwendungscode SQL Server 2005-Datenbanken abfragen und Rückrufe empfangen kann, wenn die zugrunde liegenden Daten geändert werden. Ein vergleichbares Feature für SQL Server 7.0 oder SQL Server 2000 ist jedoch nicht vorhanden. Im Gegensatz dazu unterstützt die SqlCacheDependency-Klasse von ASP.NET 2.0 SQL Server 7.0, SQL Server 2000 und SQL Server 2005. Wenn Sie ein Markerobjekt zusammen mit SqlCacheDependency im Cache platzieren und für Cachelöschungsrückrufe registrieren, stellt dies einen bequemen Weg dar, von der intelligenten Funktionalität von SqlCacheDependency zu profitieren. Wenn die zugrunde liegende Datenbank geändert wird, wird das Markerobjekt aus dem Cache entfernt und die Rückrufmethode aufgerufen, die dann geeignete Maßnahmen ergreift. In diesem Fall ist das die Aktualisierung der Sitemap (siehe Abbildung 2).

Sie können SqlSiteMapProvider bereitstellen, indem Sie die Datei SqlSiteMapProvider.cs in den Ordner App_Code der Website kopieren (ASP.NET 2.0 kompiliert Quellcodedateien in diesem Verzeichnis automatisch). Sobald der Provider bereitgestellt ist, müssen Sie ihn registrieren und als standardmäßigen SiteMapProvider festlegen. Wenn Sie das SqlCacheDependency-Feature verwenden möchten, müssen Sie dieses auch konfigurieren. Wie Sie dabei vorgehen, ist davon abhängig, ob die Sitemap in einer SQL Server 7.0-, SQL Server 2000- oder SQL Server 2005-Datenbank gespeichert wird.

Verwenden von SqlSiteMapProvider

In Abbildung 3 wird die Datei web.config dargestellt und veranschaulicht, wie SqlSiteMapProvider für die Verwendung von SQL-Cacheabhängigkeiten konfiguriert wird, wenn die Sitemap in einer SQL Server 7.0- oder SQL Server 2000-Datenbank in einer Tabelle namens SiteMap gespeichert wird. Im Abschnitt <connectionStrings> wird die Verbindungszeichenfolge SiteMapConnectionString zum Identifizieren der Datenbank definiert. Der Provider verwendet diese Informationen, um die Datenbank abzufragen und den entsprechenden Teil der Sitemap auf Änderungen hin zu überwachen. Natürlich müssen Sie die Auslassungspunkte ("…") durch eine geeignete Verbindungszeichenfolge ersetzen.

Im Abschnitt <siteMap> wird SqlSiteMapProvider registriert und als standardmäßiger SiteMapProvider festgelegt. Er enthält außerdem ein sqlCacheDependency-Attribut, das die Datenbank und die Tabelle identifiziert, in der die Sitemap-Daten gespeichert werden. Durch dieses Attribut wird SqlSiteMapProvider angewiesen, eine SQL-Cacheabhängigkeit zu erstellen, um die Sitemap-Datenbank auf Änderungen hin zu überwachen. Wenn Sie SqlSiteMapProvider ohne Cacheabhängigkeiten verwenden möchten, lassen Sie das sqlCacheDependency-Attribut einfach weg.

Im Abschnitt <sqlCacheDependency> werden die SQL-Cacheabhängikeiten in ASP.NET aktiviert und erforderliche Konfigurationsinformationen bereitgestellt. Zu diesen Informationen zählt auch das Abrufintervall, das angibt, wie oft ASP.NET die Datenbank auf Änderungen hin überprüft (in diesem Beispiel alle fünf Sekunden). Der in diesem Abschnitt angegebene Datenbankname wird dem Datenbanknamen zugeordnet, der im sqlCacheDependency-Attribut des Providers angegeben wird. Der Name der Verbindungszeichenfolge wird der Verbindungszeichenfolge im Abschnitt <connectionStrings> zugeordnet.

Damit diese Konfigurationseinstellungen funktionieren, müssen Sie zunächst die Sitemap-Datenbank und die Tabelle mit den Sitemap-Daten zur Unterstützung von SQL-Cacheabhängigkeiten vorbereiten. Hierzu müssen Sie sich lediglich zwei Minuten mit dem Dienstprogramm aspnet_regsql.exe von ASP.NET 2.0 beschäftigen: Wenn die Datenbank eine lokale Datenbank mit dem Namen SiteMapDatabase ist, führen Sie zunächst den folgenden Befehl aus, um die Datenbank vorzubereiten:

aspnet_regsql –S localhost –E –d SiteMapDatabase -ed

Wenn in der Tabelle SiteMap der Datenbank Sitemap-Daten gespeichert wurden, führen Sie anschließend den folgenden Befehl aus, um die Tabelle vorzubereiten:

aspnet_regsql –S localhost –E –d SiteMapDatabase –t SiteMap -et

Durch den ersten Befehl wird der Datenbank eine Änderungsbenachrichtigungstabelle sowie gespeicherte Prozeduren für den Zugriff auf diese Tabelle hinzugefügt. Der zweite Befehl fügt der Tabelle SiteMap einen Einfügen/Aktualisieren/Löschen-Trigger hinzu. Wenn der Trigger ausgelöst wird, fügt dieser in der Änderungsbenachrichtigungstabelle einen Eintrag ein. Durch diesen Eintrag wird angegeben, dass der Inhalt der Tabelle SiteMap geändert wurde. ASP.NET 2.0 ruft die Änderungsbenachrichtigungstabelle in vorprogrammierten Intervallen ab, um Änderungen an der Tabelle SiteMap und anderen Tabellen, die ggf. mit SQL-Cacheabhängigkeiten überwacht werden, zu ermitteln.

Wenn Sie SqlSiteMapProvider mit einer SQL Server 2005-Datenbank verwenden, müssen Sie diese Datenbank zur Verwendung von SQL-Cacheabhängigkeiten nicht vorbereiten. Sie müssen nicht einmal die Datenbank und die Tabelle identifizieren, die Sitemap-Daten enthalten. Sie müssen lediglich die SQL-Cacheabhängigkeiten mit einem sqlCacheDependency-Element aktivieren und das sqlCacheDependency-Attribut von SqlSiteMapProvider auf CommandNotification festlegen. Dieser Vorgang wird in Abbildung 4 dargestellt. Sie müssen außerdem den ASP.NET-Workerprozess mit DBO-Berechtigungen ausführen, um die SQL Server 2005-Cacheabhängigkeiten zu automatisieren.

Wenn SqlSiteMapProvider auf diese Weise konfiguriert wird, profitiert er von der in ASP.NET integrierten SQL Server 2005-Unterstützung, indem ein sqlCacheDependency-Objekt um ein SqlCommand-Objekt gewrappt wird, das die Datenbank nach Sitemap-Daten abfragt. sqlCacheDependency wiederum empfängt mithilfe von SQL Server 2005-Abfragebenachrichtigungen asynchrone Rückrufe darüber, dass die von der Abfrage zurückgegebenen Daten geändert wurden. Es werden keine Abrufe durchgeführt, und keine speziellen Tabellen, gespeicherten Prozeduren oder Trigger sind erforderlich. Wenn Sie nach einem guten Grund suchen, Ihre Datenbank auf SQL Server 2005 zu aktualisieren, ist dieses Feature bereits den Preis für den Einstieg in datengesteuerte ASP.NET-Anwendungen wert!

Erstellen der Sitemap-Datenbank

Eine Sitemap-Datenbank für SqlSiteMapProvider muss nach einem bestimmten Schema erstellt werden, das an die Darstellung hierarchischer Daten in einer relationalen Datenbank angelehnt ist. In Abbildung 5 wird ein SQL-Skript dargestellt, das eine solche Tabelle namens SiteMap erstellt und mit beispielhaften Sitemap-Knoten füllt.

Jeder in die Tabelle eingefügte Datensatz stellt einen Knoten dar und enthält Felder, die den SiteMapNode-Eigenschaften mit demselben Namen zugeordnet sind. Darüber hinaus enthalten die Datensätze Felder, die Beziehungen zwischen den Knoten angeben. Jeder Knoten muss über eine eindeutige ID verfügen, die im Feld ID gespeichert wird. Um einen Knoten einem anderen Knoten überzuordnen, legen Sie das Feld Parent des untergeordneten Knotens auf die ID des übergeordneten Knotens fest. Alle Knoten außer dem Stammknoten müssen über einen übergeordneten Knoten verfügen. Darüber hinaus kann aufgrund der Art der Implementierung von BuildSiteMap ein Knoten nur einem Knoten mit niedrigerer ID übergeordnet werden – beachten Sie die ORDER BY-Klausel in der Datenbankabfrage! Beispielsweise kann ein Knoten mit der ID 100 einem Knoten mit der ID 99 untergeordnet werden. Dieser Knoten darf jedoch keinem Knoten mit der ID 101 untergeordnet werden.

In der Standardeinstellung wird von SqlSiteMapProvider angenommen, dass die Tabelle mit den Sitemap-Daten SiteMap heißt. SqlSiteMapProvider fragt die Datenbank für Sitemap-Knoten mithilfe der proc_GetSiteMap-Prozedur ab, die auf die Tabelle SiteMap zielt. Wenn Sie den Namen der Sitemap-Tabelle ändern möchten, ändern Sie einfach den Tabellennamen in der Datenbank und in der gespeicherten Prozedur.

SqlSiteMapProvider demonstriert, wie umfangreiche neue Features ASP.NET 2.0 mithilfe von benutzerdefinierten Providern hinzugefügt werden können. Weitere Informationen zum ASP.NET 2.0-Providermodell und zum Schreiben benutzerdefinierter Provider finden Sie unter ASP.NET 2.0 Provider Model: Introduction to the Provider Model (in englischer Sprache).

Der Autor

Jeff Prosise arbeitet als Autor für MSDN Magazine und ist der Verfasser mehrerer Bücher, einschließlich Programming Microsoft .NET (Microsoft Press, 2002). Er ist außerdem Mitgründer von Wintellect, einer Firma für Softwareberatung und -schulung. Senden Sie Fragen und Kommentare für Jeff an wicked@microsoft.com (in englischer Sprache).

Anzeigen:
© 2014 Microsoft