Dela via


Example Access Site-Map Provider

Illustrates a complete Access-based site-map provider.

Example

Description

The following code example demonstrates how you can extend the StaticSiteMapProvider class to use Microsoft Access as a site-map provider. The site-map provider uses the .NET Framework Data Provider for OLE DB to connect to the Access database.

Code

Imports System
Imports System.Collections
Imports System.Collections.Specialized
Imports System.Data
Imports System.Data.OleDb
Imports System.Security.Permissions
Imports System.Web

Namespace Samples.AspNet.VB.Controls

    ' An extremely simple AccessSiteMapProvider that only supports a    ' site map node hierarchy one level deep.
    <AspNetHostingPermission(SecurityAction.Demand, Level:=AspNetHostingPermissionLevel.Minimal)> _
    PublicClass AccessSiteMapProvider
        Inherits StaticSiteMapProvider

        Private aRootNode As SiteMapNode = NothingPrivate accessConnection As OleDbConnection = Nothing
        ' This string is case sensitive.Private AccessConnectionStringName AsString = "accessSiteMapConnectionString"
        ' Implement a default constructor.PublicSubNew()
        EndSub 'New
        ' Some basic state to help track the initialization state of the provider.Private initialized AsBoolean = FalsePublicOverridableReadOnlyProperty IsInitialized() AsBooleanGetReturn initialized
            EndGetEndProperty
        ' Return the root node of the current site map.PublicOverridesReadOnlyProperty RootNode() As SiteMapNode
            GetReturn BuildSiteMap()
            EndGetEndPropertyProtectedOverridesFunction GetRootNodeCore() As SiteMapNode
            Return RootNode
        EndFunction
        ' Initialize is used to initialize the properties and any state that the        ' AccessProvider holds, but is not used to build the site map.        ' The site map is built when the BuildSiteMap method is called.PublicOverridesSub Initialize(ByVal name AsString, ByVal attributes As NameValueCollection)
            If IsInitialized ThenReturnEndIfMyBase.Initialize(name, attributes)

            ' Create and test the connection to the Microsoft Access database.            ' Retrieve the Value of the Access connection string from the            ' attributes NameValueCollection.Dim connectionString AsString = attributes(AccessConnectionStringName)

            IfNothing = connectionString OrElse connectionString.Length = 0 ThenThrowNew Exception("The connection string was not found.")
            Else
                accessConnection = New OleDbConnection(connectionString)
            EndIf
            initialized = TrueEndSub 'Initialize

        ' SiteMapProvider and StaticSiteMapProvider methods that this derived class must override.        '        ' Clean up any collections or other state that an instance of this may hold.ProtectedOverridesSub Clear()
            SyncLockMe
                aRootNode = NothingMyBase.Clear()
            EndSyncLockEndSub 'Clear

        ' Build an in-memory representation from persistent        ' storage, and return the root node of the site map.PublicOverridesFunction BuildSiteMap() As SiteMapNode

            ' Since the SiteMap class is static, make sure that it is            ' not modified while the site map is built.SyncLockMe
                ' If there is no initialization, this method is being                ' called out of order.IfNot IsInitialized ThenThrowNew Exception("BuildSiteMap called incorrectly.")
                EndIf
                ' If there is no root node, then there is no site map.If aRootNode IsNothingThen                    ' Start with a clean slate
                    Clear()

                    ' Select the root node of the site map from Microsoft Access.Dim rootNodeId AsInteger = -1

                    If accessConnection.State = ConnectionState.Closed Then
                        accessConnection.Open()
                    EndIfDim rootNodeCommand AsNew OleDbCommand("SELECT nodeid, url, name FROM SiteMap WHERE parentnodeid IS NULL", accessConnection)
                    Dim rootNodeReader As OleDbDataReader = rootNodeCommand.ExecuteReader()

                    If rootNodeReader.HasRows Then
                        rootNodeReader.Read()
                        rootNodeId = rootNodeReader.GetInt32(0)
                        ' Create a SiteMapNode that references the current StaticSiteMapProvider.
                        aRootNode = New SiteMapNode(Me, rootNodeId.ToString(), rootNodeReader.GetString(1), rootNodeReader.GetString(2))
                    ElseReturnNothingEndIf
                    rootNodeReader.Close()
                    ' Select the child nodes of the root node.Dim childNodesCommand AsNew OleDbCommand("SELECT nodeid, url, name FROM SiteMap WHERE parentnodeid = ?", accessConnection)
                    Dim rootParam AsNew OleDbParameter("parentid", OleDbType.Integer)
                    rootParam.Value = rootNodeId
                    childNodesCommand.Parameters.Add(rootParam)

                    Dim childNodesReader As OleDbDataReader = childNodesCommand.ExecuteReader()

                    If childNodesReader.HasRows ThenDim childNode As SiteMapNode = NothingWhile childNodesReader.Read()
                            childNode = New SiteMapNode(Me, _
                            childNodesReader.GetInt32(0).ToString(), _
                            childNodesReader.GetString(1), _
                            childNodesReader.GetString(2))

                            ' Use the SiteMapNode AddNode method to add                            ' the SiteMapNode to the ChildNodes collection.
                            AddNode(childNode, aRootNode)
                        EndWhileEndIf

                    childNodesReader.Close()
                    accessConnection.Close()
                EndIfReturn aRootNode
            EndSyncLockEndFunction 'BuildSiteMap

    EndClass 'AccessSiteMapProvider

EndNamespace
namespace Samples.AspNet.CS.Controls {

    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Data;
    using System.Data.OleDb;
    using System.Security.Permissions;
    using System.Web;

    /// An extremely simple AccessSiteMapProvider that only supports a/// site map node hierarchy 1 level deep.
    [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Minimal)]
    publicclass AccessSiteMapProvider : StaticSiteMapProvider
    {
        private SiteMapNode rootNode =  null;
        private OleDbConnection accessConnection = null;

        // This string is case sensitive.privatestring AccessConnectionStringName = "accessSiteMapConnectionString";

        // Implement a default constructor.public AccessSiteMapProvider () { }

        // Some basic state to help track the initialization state of the provider.privatebool initialized = false;
        publicvirtualbool IsInitialized {
            get {
                return initialized;
            }
        }
        // Return the root node of the current site map.publicoverride SiteMapNode RootNode {
            get {
                SiteMapNode temp = null;
                temp = BuildSiteMap();
                return temp;
            }
        }
        protectedoverride SiteMapNode GetRootNodeCore() {
            return RootNode;
        }
        // Initialize is used to initialize the properties and any state that the// AccessProvider holds, but is not used to build the site map.// The site map is built when the BuildSiteMap method is called.publicoverridevoid Initialize(string name, NameValueCollection attributes) {
            if (IsInitialized)
                return;

            base.Initialize(name, attributes);

            // Create and test the connection to the Microsoft Access database.// Retrieve the Value of the Access connection string from the// attributes NameValueCollection.string connectionString = attributes[AccessConnectionStringName];

            if (null == connectionString || connectionString.Length == 0)
                thrownew Exception ("The connection string was not found.");
            else
                accessConnection = new OleDbConnection(connectionString);

            initialized = true;
        }

        ////// SiteMapProvider and StaticSiteMapProvider methods that this derived class must override.///// Clean up any collections or other state that an instance of this may hold.protectedoverridevoid Clear() {
            lock (this) {
                rootNode = null;
                base.Clear();
            }
        }

        // Build an in-memory representation from persistent// storage, and return the root node of the site map.publicoverride SiteMapNode BuildSiteMap() {

            // Since the SiteMap class is static, make sure that it is// not modified while the site map is built.lock(this) {

                // If there is no initialization, this method is being// called out of order.if (! IsInitialized) {
                    thrownew Exception("BuildSiteMap called incorrectly.");
                }

                // If there is no root node, then there is no site map.if (null == rootNode) {
                    // Start with a clean slate
                    Clear();

                    // Select the root node of the site map from Microsoft Access.int rootNodeId = -1;

                    if (accessConnection.State == ConnectionState.Closed)
                        accessConnection.Open();
                    OleDbCommand rootNodeCommand =
                        new OleDbCommand("SELECT nodeid, url, name FROM SiteMap WHERE parentnodeid IS NULL",
                                         accessConnection);
                    OleDbDataReader rootNodeReader = rootNodeCommand.ExecuteReader();

                    if(rootNodeReader.HasRows) {
                        rootNodeReader.Read();
                        rootNodeId = rootNodeReader.GetInt32(0);
                        // Create a SiteMapNode that references the current StaticSiteMapProvider.
                        rootNode   = new SiteMapNode(this,
                                                     rootNodeId.ToString(),
                                                     rootNodeReader.GetString(1),
                                                     rootNodeReader.GetString(2));

                    }
                    elsereturnnull;

                    rootNodeReader.Close();
                    // Select the child nodes of the root node.
                    OleDbCommand childNodesCommand =
                        new OleDbCommand("SELECT nodeid, url, name FROM SiteMap WHERE parentnodeid = ?",
                                         accessConnection);
                    OleDbParameter rootParam = new OleDbParameter("parentid", OleDbType.Integer);
                    rootParam.Value = rootNodeId;
                    childNodesCommand.Parameters.Add(rootParam);

                    OleDbDataReader childNodesReader = childNodesCommand.ExecuteReader();

                    if (childNodesReader.HasRows) {

                        SiteMapNode childNode = null;
                        while(childNodesReader.Read()) {
                            childNode =  new SiteMapNode(this,
                                                         childNodesReader.GetInt32(0).ToString(),
                                                         childNodesReader.GetString(1),
                                                         childNodesReader.GetString(2));

                            // Use the SiteMapNode AddNode method to add// the SiteMapNode to the ChildNodes collection.
                            AddNode(childNode, rootNode);
                        }
                    }

                    childNodesReader.Close();
                    accessConnection.Close();
                }
                return rootNode;
            }
        }
    }
}
#using <System.Data.dll>
#using <System.Transactions.dll>
#using <System.EnterpriseServices.dll>
#using <System.dll>
#using <System.Web.dll>
#using <System.Configuration.dll>

usingnamespace System;
usingnamespace System::Collections;
usingnamespace System::Collections::Specialized;
usingnamespace System::Configuration;
usingnamespace System::Data;
usingnamespace System::Data::OleDb;
usingnamespace System::Security::Permissions;
usingnamespace System::Web;

/// An extremely simple AccessSiteMapProvider that only supports a/// site map node hierarchy 1 level deep.

[AspNetHostingPermission(SecurityAction::Demand,Level=AspNetHostingPermissionLevel::Minimal)]
publicrefclass AccessSiteMapProvider: public StaticSiteMapProvider
{
private:
   SiteMapNode ^ rootNode;
   OleDbConnection^ accessConnection;

   // This string is case sensitive.
   String^ AccessConnectionStringName;

public:
   // Implement a default constructor.
   AccessSiteMapProvider()
   {
      initialized = false;
      AccessConnectionStringName = "accessSiteMapConnectionString";
   }


private:

   // Some basic state to help track the initialization state of the provider.bool initialized;

public:

   propertybool IsInitialized 
   {
      virtualbool get()
      {
         return initialized;
      }

   }

   property SiteMapNode ^ RootNode 
   {

      // Return the root node of the current site map.virtual SiteMapNode ^ get() override
      {
         SiteMapNode ^ temp = nullptr;
         temp = BuildSiteMap();
         return temp;
      }

   }

protected:

   virtual SiteMapNode ^ GetRootNodeCore() override
   {
      return RootNode;
   }


public:

   // Initialize is used to initialize the properties and any state that the// AccessProvider holds, but is not used to build the site map.// The site map is built when the BuildSiteMap method is called.virtualvoid Initialize( String^ name, NameValueCollection^ attributes ) override
   {
      if ( IsInitialized )
            return;

      StaticSiteMapProvider::Initialize( name, attributes );

      // Create and test the connection to the Microsoft Access database.// Retrieve the Value of the Access connection string from the// attributes NameValueCollection.
      String^ connectionString = attributes[ AccessConnectionStringName ];
      if ( nullptr == connectionString || connectionString->Length == 0 )
            throwgcnew Exception( "The connection string was not found." );
      else
            accessConnection = gcnew OleDbConnection( connectionString );

      initialized = true;
   }


protected:

   ////// SiteMapProvider and StaticSiteMapProvider methods that this derived class must override.///// Clean up any collections or other state that an instance of this may hold.virtualvoid Clear() override
   {
      System::Threading::Monitor::Enter( this );
      try
      {
         rootNode = nullptr;
         StaticSiteMapProvider::Clear();
      }
      finally
      {
         System::Threading::Monitor::Exit( this );
      }

   }


public:

   // Build an in-memory representation from persistent// storage, and return the root node of the site map.virtual SiteMapNode ^ BuildSiteMap() override
   {
      // Since the SiteMap class is static, make sure that it is// not modified while the site map is built.
      System::Threading::Monitor::Enter( this );
      try
      {

         // If there is no initialization, this method is being// called out of order.if (  !IsInitialized )
         {
            throwgcnew Exception( "BuildSiteMap called incorrectly." );
         }

         // If there is no root node, then there is no site map.if ( nullptr == rootNode )
         {

            // Start with a clean slate
            Clear();

            // Select the root node of the site map from Microsoft Access.int rootNodeId = -1;
            if ( accessConnection->State == ConnectionState::Closed )
               accessConnection->Open();

            OleDbCommand^ rootNodeCommand = gcnew OleDbCommand
               ("SELECT nodeid, url, name FROM SiteMap WHERE parentnodeid IS NULL", accessConnection);
            OleDbDataReader^ rootNodeReader = rootNodeCommand->ExecuteReader();
            if ( rootNodeReader->HasRows )
            {
               rootNodeReader->Read();
               rootNodeId = rootNodeReader->GetInt32( 0 );

               // Create a SiteMapNode that references the current StaticSiteMapProvider.
               rootNode = gcnew SiteMapNode(this, rootNodeId.ToString(), 
                  rootNodeReader->GetString( 1 ),rootNodeReader->GetString( 2 ));
            }
            elsereturnnullptr;
            rootNodeReader->Close();

            // Select the child nodes of the root node.
            OleDbCommand^ childNodesCommand = gcnew OleDbCommand
               ("SELECT nodeid, url, name FROM SiteMap WHERE parentnodeid = ?", accessConnection);
            OleDbParameter^ rootParam = gcnew OleDbParameter( "parentid", OleDbType::Integer);
            rootParam->Value = rootNodeId;
            childNodesCommand->Parameters->Add( rootParam );
            OleDbDataReader^ childNodesReader = childNodesCommand->ExecuteReader();
            if ( childNodesReader->HasRows )
            {
               SiteMapNode ^ childNode = nullptr;
               while ( childNodesReader->Read() )
               {
                  childNode = gcnew SiteMapNode( this, 
                      System::Convert::ToString(childNodesReader->GetInt32( 0 )),
                     childNodesReader->GetString( 1 ),
                     childNodesReader->GetString( 2 ) 
                  );
                  // Use the SiteMapNode AddNode method to add// the SiteMapNode to the ChildNodes collection.
                  AddNode( childNode, rootNode );
               }
            }
            childNodesReader->Close();
            accessConnection->Close();
         }
         return rootNode;
      }
      finally
      {
         System::Threading::Monitor::Exit( this );
      }

   }

};

Comments

To create the Access table that is used by the previous code example as the site-map data store, issue the following data-definition query in a new or existing Access database, and then save the Access database with the file name Sitemap.mdb.

CREATE TABLE SiteMap
(
  URL Text (255) UNIQUE,
  NAME Text (255) NOT NULL,
  PARENTNODEID Int32,
    CONSTRAINT NODEID PRIMARY KEY (URL, NAME)
)

Populate the table with the following kinds of data, listing files that you have in your Web site or files that you can create. The following table shows an example file listing.

NODEID

URL

NAME

PARENTNODEID

1

Default.aspx

Default

null (empty cell)

2

Catalog.aspx

Catalog

1

3

Aboutus.aspx

Contact Us

1

Note

Because data sources contain differing SQL syntax, some commands will work with one data source and not with another. As a result, it is recommended that you create a site-map provider that is specific to your data source, even if you are using the .NET Framework Data Provider for ODBC or the .NET Framework Data Provider for OLE DB to access your data source (for example, SybaseSiteMapProvider, OracleSiteMapProvider, and so on).

The AccessSiteMapProvider class derives from the StaticSiteMapProvider class, and retrieves its information from an Access database using basic SQL queries as well as OleDbCommand and OleDbDataReader objects.

Finally, AccessSiteMapProvider is configured to be the default provider in the Web.config file, as shown in the following code example.

<configuration>
  <system.web>
    <siteMap defaultProvider="AccessSiteMapProvider">
      <providers>
        <add 
          name="AccessSiteMapProvider"
          type="<type name>"
          accessSiteMapConnectionString="PROVIDER=MICROSOFT.JET.OLEDB.4.0;DATA SOURCE=<path>\sitemap.mdb "/>
      </providers> 
    </siteMap>
  </system.web>
</configuration>

To customize this example, replace <type name> with the fully qualified name of the class that implements your site-map data provider. For example, in the C# code above, you would replace <type name> with Samples.AspNet.CS.Controls.AccessSiteMapProvider. If you compile your site-map data provider code and place it in the Bin directory, the <type name> string must also include the name of your compiled file without the file name extension. For example, if you compiled the C# code above into a file called Samples.AspNet.dll, you would replace <type name> with Samples.AspNet.CS.Controls.AccessSiteMapProvider.Samples.AspNet. Lastly, replace <path> with the absolute physical path to your site-map database.

Note

When you inherit from StaticSiteMapProvider, you must override the following members: BuildSiteMap and GetRootNodeCore.

Robust Programming

If you are extending the StaticSiteMapProvider class, the three most important methods are GetRootNodeCore, Initialize, and BuildSiteMap. The Clear and FindSiteMapNode methods have default implementations that are sufficient for most custom provider implementations.

See Also

Concepts

ASP.NET Site Navigation Overview

Securing ASP.NET Site Navigation

Securing Data Access

Reference

StaticSiteMapProvider

SiteMapProvider

BuildSiteMap

OleDbCommand

OleDbDataReader

SiteMapNode

SiteMap

Other Resources

ASP.NET Application Security in Hosted Environments