加入收藏 | 设为首页 | 会员中心 | 我要投稿 源码网 (https://www.900php.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

在ASP.NET 2.0中操作数据之六十:创建一个自定义的Database-Driv

发布时间:2016-11-24 04:41:08 所属栏目:MsSql教程 来源:站长网
导读:导言: ASP.NET 2.0的网站地图(site map)功能允许页面开发者在一些持久介质(persistent medium),比如一个XML文件里,自己定义一个web程序的site map.一旦定义了之后,我们可以通过System.Web命名空间的SiteMap class类或某个Web导航控件,比如SiteMapPath,

  所有的site map providers都继承自SiteMapProvider class类,该类包含了site map providers要用到的最基本的方法和属性,不过略去了很多执行细节.site map providers要用到的第二个类是StaticSiteMapProvider class类,它对SiteMapProvider class类进行了扩充,包含了更多的必要的函数.在其内部,StaticSiteMapProvider将网站地图的SiteMapNode实例存储在一个哈希表(Hashtable)里,并包含了AddNode(child, parent), RemoveNode(siteMapNode), Clear()等方法,以对哈希表里的SiteMapNodes执行添加、删除等操作.另外,XmlSiteMapProvider也继承自StaticSiteMapProvider.

  当创建自定义的site map provider时,要对StaticSiteMapProvider进行扩充,重写(overrid)2个抽象方法——BuildSiteMap 和 GetRootNodeCore. 对BuildSiteMap而言,就像它的名字暗示的那样,将网站地图的结构从某种介质里按层次结构装载进内存;而GetRootNodeCore返回的是网站地图的根目录.

  在使用某个site map provider时,需要在应用程序的配置文件里进行注册(registered)
.默认情况下,XmlSiteMapProvider class类被注册为AspNetXmlSiteMapProvider.为对额外添加的site map providers进行注册,可以在Web.config文件里添加如下的代码:

<configuration>
 <system.web>
 ...

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

  name属性可以为site map provider指派一个易读的名称;type属性决定了该site map provider的类型.当创建完我们定制的site map provider后,我们将在第七步为name 和type属性赋值.

  当第一次从SiteMap class类访问site map provider时,site map provider class类都应该被实例化,并在web应用程序的整个生命周期里都驻留在内存.

  基于性能等方面的考虑,我们应该将对驻留在内存里的网站地图结构进行数据缓存,每次调用BuildSiteMap的方法时,直接返回缓存的数据而不用重新检索数据.在任何情况下,如果我们不对BuildSiteMap对应的网站结构进行缓存的话,每次调用时,我们都需要通过“层”来重新检索产品和种类的信息(这将最终导致对数据库的查询).我们在前面的缓存章节探讨过缓存数据“过时”的问题,为此,我们要么使用基于时间,要么使用基于SQL cache dependency的缓存技术.

  注意:一个site map provider可以任意地重写(override)Initialize method方法.Initialize 方法是当site map provider第一次实例化的时候被调用的,并可以将我们在Web.config 文件的<add>元素里赋值的用户自定义属性值传递给它,比如:<add name="name" type="type" customAttribute="value" />.当一个页面开发者希望指定各种与site map provider相关的设置,而又不希望修改site map provider的代码的时候,这样做很有用.比如,假如我们希望不通过“层”而直接从数据库读取category 和 products的数据时,我们当然希望页面开发者调用Web.config文件里的数据库连接字符串,而不使用site map provider代码里的“硬编码”值.我们不打算在第六步创建的自定义site map provider里重写Initialize方法.见Jeff Prosise的文章《Storing Site Maps in SQL Server》(http://msdn.microsoft.com/msdnmag/issues/05/06/WickedCode/)

第六步:创建自定义的Site Map Provider

  要想创建一个自定义的site map provider来构建源于Northwind数据库里的categories 和 products信息的网站地图(site map),我们需要创建一个类来扩展StaticSiteMapProvider.在前面我们在App_Code文件夹里添加了一个CustomProviders文件夹,在该文件夹里添加名为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?;
 }
 }
}

  让我们考察该类的BuildSiteMap方法,它有一个lock statement声明。lock statement每次只允许“单线程操作”(one thread at a time to enter),以避免“多线程操作”之间的冲突.

(编辑:源码网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读