ASP.NET Forums2.0学习-关于论坛配置
所有有关论坛的配置信息都存放在web.config中, 在这里, 它定义了一个自定义配置节组<forums>, 里面包含两个子节<forums>和<providers>, 对于这个复杂的配置, 当然它会有一个自定义的 handler 类, 按照约定,这个类必须是实现 IConfigurationSectionHandler, 并重写它的 Create 方法. 先看看它的配置文件:
<forums
<forums
defaultProvider="SqlForumsProvider"
defaultLanguage="en-US"
forumFilesPath="/"
disableEmail="false"
disableIndexing="false"
disableThreading="false"
threadIntervalStats="15"
threadIntervalEmail="3"
passwordEncodingFormat="unicode"
allowAutoUserRegistration="false"
adminWindowsGroup="Administrators"
assignLocalAdminsAdminRole="false"
smtpServerConnectionLimit="-1"
enableLatestVersionCheck="true"
>
<providers>
<clear/>
<add
name = "SqlForumsProvider"
type = "AspNetForums.Data.SqlDataProvider, AspNetForums.SqlDataProvider"
connectionString = "server=HUANGFEI;database=Forums;uid=sa;pwd=760912;App=ASP.NET Forums"
databaseOwner = "dbo"
/>
</providers>
</forums>
</forums>
可以看到论坛的主要配置都在这里了, 当然还有一些验证的设置, 如使用窗体验证, 禁止匿名用户访问特定页面等等, 另外, 这个论坛还有自定义的 HttpHandler 和 HttpModules, 这些以后再看了. 那么, 现在看一看这个 handler 是怎么写的:
这个文件在 Components 项目的 Configuration 目录下, 叫做 ForumConfiguration.cs.
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Xml;
using System.Configuration;
using System.Web.Configuration;
namespace AspNetForums.Configuration {
// 这是最后 create 方法返回的类, 它封装了所有配置信息, 可以看到它的每一个成员对应了配置文件中的一个属性
public class ForumConfiguration {
Hashtable providers = new Hashtable();
string defaultProvider;
string defaultLanguage;
string forumFilesPath;
bool disableBackgroundThreads = false;
bool disableIndexing = false;
bool disableEmail = false;
string passwordEncodingFormat = "unicode";
int threadIntervalEmail = 1;
int threadIntervalStats = 15;
string adminWindowsGroup = "Administrators" ;
bool assignLocalAdminsAdminRole = false;
bool allowAutoUserRegistration = false;
short smtpServerConnectionLimit = -1;
bool enableLatestVersionCheck = true;
// 这只是一个封装, 使方法的调用看起来清晰一点
public static ForumConfiguration GetConfig() {
return (ForumConfiguration) ConfigurationSettings.GetConfig("forums/forums");
}
// 读取web.config中自定义节里的值, 放进成员里
internal void LoadValuesFromConfigurationXml(XmlNode node) {
XmlAttributeCollection attributeCollection = node.Attributes;
defaultProvider = attributeCollection["defaultProvider"].Value;
defaultLanguage = attributeCollection["defaultLanguage"].Value;
forumFilesPath = attributeCollection["forumFilesPath"].Value;
// 如果配置的值类型不对, 转换失败, 就使用默认值
try {
disableBackgroundThreads = Boolean.Parse(attributeCollection["disableThreading"].Value);
} catch {
disableBackgroundThreads = false;
}
try {
disableIndexing = Boolean.Parse(attributeCollection["disableIndexing"].Value);
} catch {
disableIndexing = false;
}
try {
passwordEncodingFormat = attributeCollection["passwordEncodingFormat"].Value;
} catch {
passwordEncodingFormat = "unicode";
}
try {
disableEmail = Boolean.Parse(attributeCollection["disableEmail"].Value);
} catch {
disableEmail = false;
}
try {
threadIntervalStats = int.Parse(attributeCollection["threadIntervalStats"].Value);
} catch {
threadIntervalStats = 15;
}
try {
threadIntervalEmail = int.Parse(attributeCollection["threadIntervalEmail"].Value);
} catch {
threadIntervalEmail = 1;
}
try {
adminWindowsGroup = attributeCollection["adminWindowsGroup"].Value;
} catch {
adminWindowsGroup = "Administrators";
}
try
{
assignLocalAdminsAdminRole = Boolean.Parse( attributeCollection["assignLocalAdminsAdminRole"].Value );
} catch {
assignLocalAdminsAdminRole = false;
}
try {
allowAutoUserRegistration = Boolean.Parse( attributeCollection["allowAutoUserRegistration"].Value );
} catch {
allowAutoUserRegistration = false;
}
try {
smtpServerConnectionLimit = Int16.Parse( attributeCollection["smtpServerConnectionLimit"].Value );
} catch {
smtpServerConnectionLimit = -1;
}
try {
enableLatestVersionCheck = Boolean.Parse( attributeCollection["enableLatestVersionCheck"].Value );
} catch {
enableLatestVersionCheck = true;
}
// 读取 forums/forums 的子节点, 其实只有一个 <provicers>
foreach (XmlNode child in node.ChildNodes) {
if (child.Name == "providers")
GetProviders(child);
}
}
// 如果读到了 <providers> , 那么继续读下面的子节点, 在web.config里我只看至 <clear/>和<add>两个
// 可以在这里添加新的数据提供, 当然也可以移除
internal void GetProviders(XmlNode node) {
foreach (XmlNode provider in node.ChildNodes) {
switch (provider.Name) {
// 如果遇见 add 节, 就将属性 name 的值, 和封装了数据提供信息的类 Provider 作为键值对存放
// 到这个叫 providers 的哈希表里. 下面是相应的移除及清空操作.
case "add" :
providers.Add(provider.Attributes["name"].Value, new Provider(provider.Attributes) );
break;
case "remove" :
providers.Remove(provider.Attributes["name"].Value);
break;
case "clear" :
providers.Clear();
break;
}
}
}
// 这些是供外部访问的公共属性, 实际是返回相应的成员的值
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 bool IsBackgroundThreadingDisabled { get { return disableBackgroundThreads; } }
public bool IsIndexingDisabled { get { return disableIndexing; } }
public string PasswordEncodingFormat { get{ return passwordEncodingFormat; } }
public bool IsEmailDisabled {
get {
return disableEmail;
}
}
public int ThreadIntervalEmail {
get {
return threadIntervalEmail;
}
}
public int ThreadIntervalStats {
get {
return threadIntervalStats;
}
}
public string AdminWindowsGroup {
get {
return adminWindowsGroup;
}
}
public bool AssignLocalAdminsAdminRole
{
get
{
return assignLocalAdminsAdminRole;
}
}
public bool AllowAutoUserRegistration {
get {
return allowAutoUserRegistration;
}
}
public short SmtpServerConnectionLimit {
get {
return smtpServerConnectionLimit;
}
}
public bool EnableLatestVersionCheck {
get {
return enableLatestVersionCheck;
}
}
}
// 这个类封装了关于数据提供的信息
public class Provider {
string name;
string providerType;
NameValueCollection providerAttributes = new NameValueCollection();
public Provider (XmlAttributeCollection attributes) {
name = attributes["name"].Value;
providerType = attributes["type"].Value;
// 如果属性里除了 name 及 type 之外还有其它的, 那就把它们装进 NameValueCollection 里面
foreach (XmlAttribute attribute in attributes) {
if ( (attribute.Name != "name") && (attribute.Name != "type") )
providerAttributes.Add(attribute.Name, attribute.Value);
}
}
public string Name {
get {
return name;
}
}
public string Type {
get {
return providerType;
}
}
public NameValueCollection Attributes {
get {
return providerAttributes;
}
}
}
// 这个类就是自定义节的 handler 类, 只需实现 Create 方法, 它返回前面的 ForumConfiguration 类
internal class ForumsConfigurationHandler : IConfigurationSectionHandler {
public virtual object Create(Object parent, Object context, XmlNode node) {
ForumConfiguration config = new ForumConfiguration();
config.LoadValuesFromConfigurationXml(node);
return config;
}
}
}
其实在仅仅写了 handler 类是不够的, 还在要 web.config 中注册:
<configSections>
<sectionGroup name="forums">
<section name="forums" type="AspNetForums.Configuration.ForumsConfigurationHandler, AspNetForums.Components" />
</sectionGroup>
</configSections>
所有配置文件中的节都是这么定义的, 可以 machine.config 中看到所有已知节点的配置信息, 它们被包含在<configSections>标签对中, type 的值中, 前面部分是这个 handler 类的全名, 后面是它所在的程序集.