ASP.NET自定义Web.config中的Section
本文将根据通过在Web.config中,自定义一段Section,来设置用户密码保存时所使用的Hash方法,来讲解如何使用自定义Section。
需求
我们的需求是这样的,在web.config中,让用户通过如下的自定义Section,来定义使用什么Hash方法。
<ezfx>
<hashAlgorithms default="sha256">
<!--这里的Hash方法,必须是抽象类System.Security.Cryptography.HashAlgorithm的子类。-->
<hashAlgorithm name="sha256"
type="System.Security.Cryptography.SHA256Managed, mscorlib" />
</hashAlgorithms>
</ezfx>
其中ezfx是框架的名字,hashAlgorithms是hash算法的集合。它有一个属性,叫default,就是默认的hash方法,这个用于存密码的时候使用。hashAlgorithems下面,就是hashAlgorithm。hashAlgorithm有两个属性,name和type,name是hash方法的名字,type是这个hash方法对应的类。这样,我们需要使用某个方法的时候,只要给出名字就可以了。
实现
为了实现这个需求,我们需要:
一、在Web.config中的configSections中,申明这个section。包括指定其SectionHandler。
二、自定义一个Config类,以接受SectionHandler的返回值,并提供程序调用。
三、编写SectionHandler,以解析自定义的Section。
四、把自定义的Config类,作为一个静态类(VB.NET里面的Module)的属性。即持久化。
申明
申明就是告诉Web.config,下面有一段我的自定义代码。申明自定义Section的时候,需要指定Section的名字,类型(即SectionHandler)。如下:
<configSections>
<sectionGroup name="ezfx">
<section name="hashAlgorithms" type="Ezfx.Cryptography.HashAlgorithmsSectionHandler,
Ezfx.Cryptography" />
</sectionGroup>
</configSections>
自定义Config类
自定义一个Config类,这样,自定义的Section在CLR中就有了自己的代表(Representation)。自定义Config类如下:
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
namespace Ezfx.Cryptography
{
public class HashAlgorithmsConfiguration : ICloneable
{
public HashAlgorithm Default { get;internal set; }
public string DefaultName { get; internal set; }
private Dictionary<string, HashAlgorithm> _HashAlgorithms;
public Dictionary<string, HashAlgorithm> HashAlgorithms
{
get
{
if (_HashAlgorithms == null)
{
_HashAlgorithms = new Dictionary<string, HashAlgorithm>();
}
return _HashAlgorithms;
}
}
object ICloneable.Clone()
{
return Clone();
}
protected virtual object Clone()
{
return MemberwiseClone();
}
}
}
Section Handler
Section Handler的任务,就是读取Web.config中的XML,并输出一个类型为Object的对象。在这里,我们可以把XML里面的值和HashAlgorithmsConfiguration对应起来,并返回HashAlgorithmsConfiguration。
using System;
using System.Configuration;
using System.Security.Cryptography;
using System.Xml;
namespace Ezfx.Cryptography
{
public sealed class HashAlgorithmsSectionHandler : IConfigurationSectionHandler
{
public object Create(object parent, object configContext, XmlNode section)
{
if (section == null)
throw new ArgumentNullException("section");
HashAlgorithmsConfiguration config;
if (parent != null)
{
HashAlgorithmsConfiguration parentConfig = (HashAlgorithmsConfiguration)parent;
config = (HashAlgorithmsConfiguration)((ICloneable)parentConfig).Clone();
}
else
{
config = new HashAlgorithmsConfiguration();
}
config.DefaultName = ((XmlElement)section).GetAttribute("default");
foreach (XmlElement subElement in section.ChildNodes)
{
string name = subElement.GetAttribute("name");
string typeName = subElement.GetAttribute("type");
Type t = Type.GetType(typeName);
HashAlgorithm dealer = (HashAlgorithm)Activator.CreateInstance(t);
if (name == config.DefaultName)
{
config.Default = dealer;
}
config.HashAlgorithms.Add(name, dealer);
}
return config;
}
}
}
持久化
把自定义的Config类,作为一个静态类(VB.NET里面的Module)的属性。有人会问,如果我修改了web.config怎么办?其实,一旦web.config被修改了,ASP.NET程序就会重新启动,重新加载Web.config,所以,大家可以放心的把配置信息放在静态类里面。
延伸
schema
经过上面的努力,现在程序终于搞定了。但是,还是美中不足。如图:
Error List里面,Message列表多出了不少东西。其中一条是:Could not find schema information for the element ‘ezfx’。这样看了不是很不爽么。经过在Google上的一番求索,终于找到了方案。
方案就是,写一个schema文件,并让Web.config去引用这个文件。
Schema文件如下:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema version="1.0" elementFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Copyright 2011 by Zhou Weiguang, Licensed under the Apache License, Version 2.0 -->
<xs:element name="ezfx" type="ezfx">
</xs:element>
<xs:complexType name="ezfx">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element minOccurs="0" maxOccurs="1" name="hashAlgorithms" type="hashAlgorithms" />
</xs:choice>
</xs:sequence>
</xs:complexType>
<xs:complexType name="hashAlgorithms">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element minOccurs="0" maxOccurs="1" name="hashAlgorithm" type="hashAlgorithm" />
</xs:choice>
</xs:sequence>
<xs:attribute name="default" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="hashAlgorithm">
<xs:attribute name="name" type="xs:string" use="required" >
</xs:attribute>
<xs:attribute name="type" type="xs:string" use="required" />
</xs:complexType>
</xs:schema>
接着,让Web.config引用这个Schema。在ezfx上,加两个属性,如下:
<ezfx ez:noNamespaceSchemaLocation="ezfxConfig.xsd" xmlns:ez="http://www.w3.org/2001/XMLSchema-instance">