asp.net Forums 之配置,缓存,多数据访问

在上一篇文章中,我谈到了asp.net Forums 之控件研究,这次我们来谈谈asp.net Forums 的配置、缓存和多数据访问。

一、配置

ANF的配置是通过ForumConfiguration类,ForumConfiguration类位于AspNetForums.Configuration命名空间下。

  

代码
#region VSS

/*
* $Header: /HiForums/Components/Configuration/ForumConfiguration.cs 1 05-10-26 15:04 Jacky $
*
* $History: ForumConfiguration.cs $
*
* ***************** Version 1 *****************
* User: Jacky Date: 05-10-26 Time: 15:04
* Created in $/HiForums/Components/Configuration
*
* ***************** Version 1 *****************
* User: Jacky Date: 05-10-21 Time: 14:20
* Created in $/HiForums/Components/Configuration
*
* ***************** Version 3 *****************
* User: Jacky Date: 05-09-20 Time: 19:23
* Updated in $/ASP.NET Forums/Components/Configuration
*
* ***************** Version 2 *****************
* User: Jacky Date: 05-09-20 Time: 1:36
* Updated in $/ASP.NET Forums/Components/Configuration
*/

#endregion

using System;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Web;
using System.Web.Caching;
using System.Xml;
using System.Configuration;
using System.Xml.Serialization;
using AspNetForums.Components;
using AspNetForums.Enumerations;

namespace AspNetForums.Configuration
{
// *********************************************************************
// ForumConfiguration
//
/// <summary>
/// 读取论坛配置信息,根据CS结构重构.
/// by venjiang 2005/10/25
/// </summary>
///
// ***********************************************************************/
public class ForumConfiguration
{
#region 成员字段
public static readonly string CacheKey = "ForumsConfiguration";
private Hashtable providers = new Hashtable();
private Hashtable extensions = new Hashtable();
private static readonly Cache cache = HttpRuntime.Cache;
private string defaultProvider;
private string defaultLanguage;
private string forumFilesPath;
private bool disableBackgroundThreads = false;
private bool disableIndexing = false;
private bool disableEmail = false;
private string passwordEncodingFormat = "unicode";
private int threadIntervalEmail = 15;
private int threadIntervalStats = 15;
//private SystemType systemType = SystemType.Self;
private short smtpServerConnectionLimit = -1;
private bool enableLatestVersionCheck = true;
private string uploadFilesPath = "/Upload/";
private XmlDocument XmlDoc = null;
#endregion

#region 构造器
public ForumConfiguration(XmlDocument doc)
{
XmlDoc
= doc;
LoadValuesFromConfigurationXml();
}
#endregion

#region 获取XML节点
public XmlNode GetConfigSection(string nodePath)
{
return XmlDoc.SelectSingleNode(nodePath);
}

#endregion
/*
public static ForumConfiguration GetConfig()
{
return (ForumConfiguration) ConfigurationSettings.GetConfig("forums/forums");
}
*/
#region 获取配置信息实例
public static ForumConfiguration GetConfig()
{
ForumConfiguration config
= cache.Get(CacheKey) as ForumConfiguration;
if(config == null)
{
string path;
if(HttpContext.Current != null)
path
= HttpContext.Current.Server.MapPath("~/Forums.config");
else
path
= Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "Forums.config";

XmlDocument doc
= new XmlDocument();
doc.Load(path);
config
= new ForumConfiguration(doc);
cache.Insert(CacheKey,config,
new CacheDependency(path),DateTime.MaxValue,TimeSpan.Zero,CacheItemPriority.AboveNormal,null);

//cache.ReSetFactor(config.CacheFactor);
}
return config;

}
#endregion

#region 加载配置文件设置
internal void LoadValuesFromConfigurationXml()
{
XmlNode node
= GetConfigSection("Forums/Core");
XmlAttributeCollection attributeCollection
= node.Attributes;

// 默认数据提供者
XmlAttribute att = attributeCollection["defaultProvider"];
if(att != null)
defaultProvider
= att.Value;
// 默认语言
att = attributeCollection["defaultLanguage"];
if(att != null)
defaultLanguage
=att.Value;
else
defaultLanguage
= "zh-CN";
// 论坛路径
att = attributeCollection["forumFilesPath"];
if(att != null)
forumFilesPath
= att.Value;
else
forumFilesPath
= "/";
// 禁用后台线程
att = attributeCollection["disableThreading"];
if(att != null)
disableBackgroundThreads
= bool.Parse(att.Value);
else
disableBackgroundThreads
= false;
// 禁止索引
att = attributeCollection["disableIndexing"];
if(att != null)
disableIndexing
= bool.Parse(att.Value);
else
disableIndexing
= false;
// 禁止邮件
att = attributeCollection["disableEmail"];
if(att != null)
disableEmail
= bool.Parse(att.Value);
else
disableEmail
= false;
// 密码加密格式
att = attributeCollection["passwordEncodingFormat"];
if(att != null)
passwordEncodingFormat
= att.Value;
else
passwordEncodingFormat
= "unicode";
// 后中统计状态
att = attributeCollection["threadIntervalStats"];
if(att != null)
threadIntervalStats
= int.Parse(att.Value);
else
threadIntervalStats
= 15;
// 邮件队列发送间隔
att = attributeCollection["threadIntervalEmail"];
if(att != null)
threadIntervalEmail
= int.Parse(att.Value);
else
threadIntervalEmail
= 15;
// SMTP服务器设置
att = attributeCollection["smtpServerConnectionLimit"];
if(att != null)
smtpServerConnectionLimit
= short.Parse(att.Value);
else
smtpServerConnectionLimit
= -1;
// 版本检查
att = attributeCollection["enableLatestVersionCheck"];
if(att != null)
enableLatestVersionCheck
= bool.Parse(att.Value);
// 上传文件路径
att = attributeCollection["uploadFilesPath"];
if(att != null)
uploadFilesPath
= att.Value;

// 读取子节点
foreach (XmlNode child in node.ChildNodes)
{
if (child.Name == "providers")
GetProviders(child, providers);

if (child.Name == "extensionModules")
GetProviders(child, extensions);

}
}

#endregion

#region 获取配置文件节点Provider
internal void GetProviders(XmlNode node, Hashtable table)
{
foreach (XmlNode provider in node.ChildNodes)
{
switch (provider.Name)
{
case "add":
table.Add(provider.Attributes[
"name"].Value, new Provider(provider.Attributes));
break;

case "remove":
table.Remove(provider.Attributes[
"name"].Value);
break;

case "clear":
table.Clear();
break;

}

}

}
#endregion

#region 公有属性
// Properties
//
public string DefaultLanguage
{
get { return defaultLanguage; }
}

public string ForumFilesPath
{
get { return forumFilesPath; }
}

public string DefaultProvider
{
get { return defaultProvider; }
}

public Hashtable Providers
{
get { return providers; }
}

public Hashtable Extensions
{
get { return extensions; }
}

public bool IsBackgroundThreadingDisabled
{
get { return disableBackgroundThreads; }
}

public bool IsIndexingDisabled
{
get { return disableIndexing; }
}

public string PasswordEncodingFormat
{
get { return passwordEncodingFormat; }
}

public string UploadFilesPath
{
get { return uploadFilesPath; }
}

public bool IsEmailDisabled
{
get { return disableEmail; }
}

public int ThreadIntervalEmail
{
get { return threadIntervalEmail; }
}

public int ThreadIntervalStats
{
get { return threadIntervalStats; }
}

public short SmtpServerConnectionLimit
{
get { return smtpServerConnectionLimit; }
}

public bool EnableLatestVersionCheck
{
get { return enableLatestVersionCheck; }
}
#endregion
}

/// <summary>
/// 数据提供者实体类
/// </summary>
public class Provider
{
#region 成员字段
private string name;
private string providerType;
private ExtensionType extensionType;
private NameValueCollection providerAttributes = new NameValueCollection();
#endregion

#region 构造器
public Provider(XmlAttributeCollection attributes)
{
// Set the name of the provider
//
name = attributes["name"].Value;

// Set the extension type
//
try
{
extensionType
= (ExtensionType)Enum.Parse(typeof(ExtensionType), attributes["extensionType"].Value, true);
}
catch
{
// Occassionally get an exception on parsing the extensiontype, so set it to Unknown
extensionType = ExtensionType.Unknown;
}

providerType
= attributes["type"].Value;

// Store all the attributes in the attributes bucket
//
foreach (XmlAttribute attribute in attributes)
{
if ((attribute.Name != "name") && (attribute.Name != "type"))
providerAttributes.Add(attribute.Name, attribute.Value);

}

}
#endregion

#region 公有属性
public string Name
{
get { return name; }
}

public string Type
{
get { return providerType; }
}

public ExtensionType ExtensionType
{
get { return extensionType; }
}


public NameValueCollection Attributes
{
get { return providerAttributes; }
}

#endregion
}
}
// *********************************************************************
// ForumsConfigurationHandler
//
/// <summary>
/// Class used by ASP.NET Configuration to load ASP.NET Forums configuration.
/// </summary>
///
// ***********************************************************************/
/*
internal class ForumsConfigurationHandler : IConfigurationSectionHandler
{
public virtual object Create(Object parent, Object context, XmlNode node)
{
ForumConfiguration config = new ForumConfiguration();
config.LoadValuesFromConfigurationXml(node);
return config;
}

}
*/

这个配置文件配置了ANF的默认数据提供者、默认语言、论坛路径、是滞禁用后台线程、是滞禁止索引、是否禁止邮件、密码加密格式、线程间隔状态、邮件队列发送间隔、SMTP服务器设置、版本检查
上传文件路径、数据提供者、自定义HttpModule等。主要方法为GetConfig():

代码
public static ForumConfiguration GetConfig()
{
ForumConfiguration config
= cache.Get(CacheKey) as ForumConfiguration;
if(config == null)
{
string path;
if(HttpContext.Current != null)
path
= HttpContext.Current.Server.MapPath("~/Forums.config");
else
path
= Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "Forums.config";

XmlDocument doc
= new XmlDocument();
doc.Load(path);
config
= new ForumConfiguration(doc);
cache.Insert(CacheKey,config,
new CacheDependency(path),DateTime.MaxValue,TimeSpan.Zero,CacheItemPriority.AboveNormal,null);

//cache.ReSetFactor(config.CacheFactor);
}
return config;

}

在此方法中,首先从Cache缓存中获取配置信息,如配置信息还未缓存,则读敢配置文件。配置文件位于网站根目录下的Forums.config文件。读取配置文件的内容后插入缓存中以便下次使用。
Forums.config文件如下:

代码
<?xml version="1.0" encoding="utf-8" ?>
<Forums>
<Core defaultLanguage="zh-CN"
forumFilesPath
="/"
disableEmail
="false"
disableIndexing
="true"
disableThreading
="false"
threadIntervalStats
="15"
threadIntervalEmail
="15"
smtpServerConnectionLimit
="-1"
passwordEncodingFormat
="unicode"
enableLatestVersionCheck
="false"
uploadFilesPath
="/Upload/"
defaultProvider
="SqlForumsProvider">
<providers>
<clear />
<add name="LocalSqlForumsProvider" type="AspNetForums.Data.SqlDataProvider, AspNetForums.SqlDataProvider"
connectionString
="server=.;database=Forums;uid=sa;pwd=" databaseOwner="dbo" />
<add name="SqlForumsProvider" type="AspNetForums.Data.SqlDataProvider, AspNetForums.SqlDataProvider"
connectionStringName
= "SiteSqlServer" databaseOwnerStringName = "SiteSqlServerOwner" />
<add name="SqlDataProviderNonDbo" type="AspNetForums.Data.SqlDataProviderNonDbo, AspNetForums.SqlDataProviderNonDbo"
connectionStringName
= "SiteSqlServer" databaseOwnerStringName = "SiteSqlServerOwner" />
</providers>
<extensionModules>
<add name="PassportAuthentication" extensionType="Security" type="Telligent.CommunityServer.Security.PassportAuthentication, Telligent.CommunityServer.SecurityModules" />
<add name="WindowsAuthentication" extensionType="Security" type="Telligent.CommunityServer.Security.WindowsAuthentication, Telligent.CommunityServer.SecurityModules"
allowAutoUserRegistration
="true" adminWindowsGroup="Administrators" adminWindowsGroupIsSystemAdministrator="true" />
<add name="FormsAuthentication" extensionType="Security" type="Telligent.CommunityServer.Security.FormsAuthentication, Telligent.CommunityServer.SecurityModules"
allowAutoUserRegistration
="true" userEmailAddressCookie="CSUserEmailAddress" useEncryptedEmailAddressCookie="false" />
</extensionModules>
</Core>
</Forums>

二、缓存

通过在类中添加private static readonly Cache cache = HttpRuntime.Cache;来实现。

三、多数据访问

ANF的数据访问基类是ForumsDataProvider类,ForumsDataProvider这个类位于AspNetForums.Components命名空间下。这是一个抽象类,你可以去实现你的SQL子类或其他子类。主要方法为两个实例化方法。
实例化方法一:

public static ForumsDataProvider Instance()
{
// 理论上应该出现不了null,但程序运行确实出现过.原因待查.
if(_defaultInstance == null)
CreateDefaultCommonProvider();
return _defaultInstance;
}

       
在第一个实例化方法中,使用了单例设计模式,如果默认实例为空,则创建默认实例,方法如下:

代码
private static void CreateDefaultCommonProvider()
{
ForumConfiguration config
= ForumConfiguration.GetConfig();
Provider sqlForumsProvider
= (Provider) config.Providers[config.DefaultProvider];
_defaultInstance
= DataProviders.CreateInstance(sqlForumsProvider) as ForumsDataProvider;
}


首先获取配置信息,通过配置信息中的默认数据提供者来创建默认实例。

实例化方法二:

代码
public static ForumsDataProvider Instance (Provider dataProvider)
{
ForumsDataProvider fdp
= cache.Get(dataProvider.Name) as ForumsDataProvider;
if(fdp == null)
{
fdp
= DataProviders.Invoke(dataProvider) as ForumsDataProvider;
cache.Insert(dataProvider.Name,fdp,
null,DateTime.MaxValue,TimeSpan.Zero,CacheItemPriority.AboveNormal,null);
}
return fdp;
}


在第二个实例化方法中,使用了缓存,通过给定的提供者,如果缓存中有,则直接调用。如果没有,则创建。创建后插入缓存以便下次使用。

其它抽象方法为子类需要实现的真正的数据访问方法。

欢迎大家指正。

原文地址:https://www.cnblogs.com/Jesong/p/1751524.html