I. Theoretical knowledge
Inherited from sitemapprovider
To implement site navigation, sitemap is the most convenient feature in ASP. NET 2.0. If xmlsitemapprovider is used only, the navigation can only be reflected from the static sitemap file, and the navigation structure stored in the database cannot be reflected. To generate Site Navigation Based on databases, you must develop your own sitemapprovider.
Sitemapprovider has four methods to override: findsitemapnode (get Node Based on URL), getchildnodes (get all child nodes), and getparentnode (get parent node) and getrootnodecore (get the root node within the management scope of the sitemapprovider ). For sitemap users, for example, sitemapdatasource, the above four methods can always complete sitemap-related queries within a limited number of steps, such as expanding sitemap at several layers, and obtain the path from the root sitemapnode to a specific sitemapnode. Therefore, you only need to ensure that your sitemapprovider class correctly implements the above four methods, and you can use them for any sitemap query.
The flexibility of sitemapprovider is very high. It can construct a strict tree or even a directed graph. For example, a node can only have one parent node, but it can be a child node of multiple nodes. This does not seem so easy to understand, but you can do so, because sitemapprovider can be designed to include the same specific node in the list returned when multiple different nodes are input to the getchildnodes method. If you don't think you need this flexibility, but you need to use a strict tree, and the tree is relatively static (that is, a construction tree can be used for multiple queries ), you should consider inheriting from staticsitemapprovider rather than sitemapprovider.
Inherited from staticsitemapprovider
The method for implementing staticsitemapprovider is different from that for implementing sitemapprovider. If you choose to inherit from staticsitemapprovider, you determine that the navigation model is a strict tree. You only need to describe the tree structure from the persistent data, and the basic functions of staticsitemapprovider will help you maintain copies of the tree structure in the memory, in this way, three of the four methods to be rewritten are provided, and only getrootnodecore needs to be rewritten by yourself.
Inherited from staticsitemapprovider, in addition to getrootnodecore, you also need to override the buildsitemap method, which is exactly where staticsitemapprovider builds the tree structure in memory. The methods required for the build operation are also provided by staticsitemapprovider, which are the addnode and removenode methods respectively. In addition, the clear method can clear the entire tree structure in the memory.
Combined with databases
Generally, you need to override the initialize, getrootnodecore, and buildsitemap methods of staticsitemapprovider to construct sitemap through a database.
The initialize method inherits from providerbase, which is the base class of all provider classes. In the initialize method, you can receive the name and configuration information of this provider. You can write connectionstring in this provider on the web. in the configuration section of config, these configuration key values are passed in during Initialize. You can save the passed connectionstring to the private variable of provider at this time, but do not construct the tree in initialize, because it is called only once.
Getrootnodecore is used to return the root node within the scope of responsibility of this sitemapprovider. Because the whole sitemap can be composed of sitemap provided by multiple sitemapproviders, the root node within the scope is critical when it crosses the sitemapprovider responsibility range boundary. The usual practice is to use a private variable to save the sitemapnode representing the root node when implementing your own staticsitemapprovider, And the sitemapnode is built by buildsitemap.
Buildsitemap is the core of the staticsitemapprovider derived class. here you need to call the clear method to clear the original tree, query the database, and use the addnode and removenode methods to construct a new tree. It should be noted that this method must be thread-safe, because multiple clients may access the page, resulting in querying data from your staticsitemapprovider at the same time, So multiple threads call the buildsitemap method at the same time. Therefore, in the buildsitemap method that is rewritten, the lock (this) is usually performed after the clear operation is started, and then the tree construction starts.
Notes
If you like other methods of sitemapprovider and staticsitemapprovider, you can rewrite them. Remember to ensure thread security. The built-in methods of staticsitemapprovider are thread-safe. If you call them directly, you can rely on the internal lock instead of lock yourself.
If your sitemapprovider is to be the next-level sitemapprovider of xmlsitemapprovider, it is declared in the static sitemap File<Sitemapnode provider = "somesitemapprovider"/>. If your sitemapprovider references another sitemapprovider, the parent sitemapprovider only needs to include the root node of the next level of sitemap in its own sitemap. This can usually be done through sitemapprovider at the next level. get the getrootnodecore method and set the parentprovider attribute of the sub-sitemapprovider to the parent sitemapprovider.
Ii. Demo
/// <Summary>
/// Sqlsitemapprovider
/// </Summary>
Public class sqlsitemapprovider: staticsitemapprovider
{
Private string _ strcon;
Private int _ indexid, _ indextitle, _ indexurl, _ indexdesc, _ indexparent;
// Node
Private sitemapnode _ node;
// Node dictionary table
Private dictionary <int, sitemapnode> _ nodes = new dictionary <int, sitemapnode> ();
// Used in singleton Mode
Private readonly object _ Lock = new object ();
/// <Summary>
/// Initialization
/// </Summary>
/// <Param name = "name"> </param>
/// <Param name = "Config"> </param>
Public override void initialize (string name, namevaluecollection config)
{
// Verify that config exists
If (Config = NULL)
Throw new argumentnullexception ("Config cannot be null ");
// If no provider exists, it is set as the default
If (string. isnullorempty (name ))
Name = "sqlsitemapprovider ";
// Add a description without a description
If (string. isnullorempty (config ["Description"])
{
Config. Remove ("Description ");
Config. Add ("Description", "sqlsitemapprovider ");
}
// Call the initialization method of the base class
Base. initialize (name, config );
// Initialize the connection string
String constringname = config ["connectionstringname"];
If (string. isnullorempty (constringname ))
Throw new providerexception ("connectionstringname not found ");
Config. Remove ("connectionstringname ");
If (webconfigurationmanager. connectionstrings [constringname] = NULL)
Throw new providerexception ("connection string not found according to connectionstringname ");
// Obtain the connection string
_ Strcon = webconfigurationmanager. connectionstrings [constringname]. connectionstring;
If (string. isnullorempty (_ strcon ))
Throw new providerexception ("the connection string is empty ");
Clear ();
Sitmapbll. producttrcipsitmap ();
}
/// <Summary>
/// Load the site map information from the persistent storage area and build it in the memory
/// </Summary>
/// <Returns> </returns>
Public override sitemapnode buildsitemap ()
{
Lock (_ Lock)
{
// Implementation of Singleton Mode
If (_ node! = NULL)
Return _ node;
Sqlconnection connection = new sqlconnection (_ strcon );
Try
{
Sqlcommand command = new sqlcommand ("sp_getsitemap", connection );
Command. commandtype = commandtype. storedprocedure;
Connection. open ();
Sqldatareader reader = command. executereader ();
// Obtain the index of each field
_ Indexid = reader. getordinal ("ID ");
_ Indexurl = reader. getordinal ("url ");
_ Indextitle = reader. getordinal ("title ");
_ Indexdesc = reader. getordinal ("Description ");
_ Indexparent = reader. getordinal ("parent ");
If (reader. Read ())
{
// Add the first record as the root node
_ Node = createsitemapnodefromdatareader (Reader );
Addnode (_ node, null );
// Construct a node tree
While (reader. Read ())
{
// Add a node to the Site Map
Sitemapnode node = createsitemapnodefromdatareader (Reader );
Addnode (node, getparentnodefromdatareader (Reader ));
}
}
Reader. Close ();
}
Catch (exception ex)
{
Throw new exception (ex. tostring ());
}
Finally
{
Connection. Close ();
}
// Return sitemapnode
Return _ node;
}
}
/// <Summary>
/// The root node of all nodes currently managed by the current provider will be retrieved
/// </Summary>
/// <Returns> </returns>
Protected override sitemapnode getrootnodecore ()
{
// Clear ();
Lock (_ Lock)
{
Return buildsitemap ();
}
}
/// <Summary>
/// Clear the nodes in the site map.
/// </Summary>
Protected override void clear ()
{
Lock (_ Lock)
{
_ Nodes = new dictionary <int, sitemapnode> ();
Base. Clear ();
}
}
/// <Summary>
/// Return sitemapnode based on the data read by datareader
/// </Summary>
/// <Param name = "Reader"> dbdatareader </param>
/// <Returns> </returns>
Private sitemapnode createsitemapnodefromdatareader (dbdatareader reader)
{
If (reader. isdbnull (_ indexid ))
Throw new providerexception ("No ID found ");
Int id = reader. getint32 (_ indexid );
If (_ nodes. containskey (ID ))
Throw new providerexception ("Duplicate ID is not allowed ");
// Obtain the value of the corresponding field based on the field Index
String title = reader. isdbnull (_ indextitle )? Null: reader. getstring (_ indextitle). Trim ();
String url = reader. isdbnull (_ indexurl )? Null: reader. getstring (_ indexurl). Trim ();
String description = reader. isdbnull (_ indexdesc )? Null: reader. getstring (_ indexdesc). Trim ();
// Create a sitemapnode
Sitemapnode node = new sitemapnode (this, id. tostring (), URL, title, description );
// Add this sitemapnode to the node dictionary table.
_ Nodes. Add (ID, node );
// Return the sitemapnode
Return node;
}
/// <Summary>
/// Obtain the sitemapnode of the parent node
/// </Summary>
/// <Param name = "Reader"> </param>
/// <Returns> </returns>
Private sitemapnode getparentnodefromdatareader (dbdatareader reader)
{
If (reader. isdbnull (_ indexparent ))
Throw new providerexception ("parent node cannot be blank ");
Int pid = reader. getint32 (_ indexparent );
If (! _ Nodes. containskey (PID ))
Throw new providerexception ("Duplicate node ID ");
// Return the sitemapnode of the parent node
Return _ nodes [pid];
}
}