在上一篇文章中,我谈到了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;
}
在第二个实例化方法中,使用了缓存,通过给定的提供者,如果缓存中有,则直接调用。如果没有,则创建。创建后插入缓存以便下次使用。
其它抽象方法为子类需要实现的真正的数据访问方法。
欢迎大家指正。