通過繼承ConfigurationValidatorBase類,使用者可以自訂一個配置系統的驗證器,可是今天使用這種方法發現了一個問題:每個ConfigurationProperty在驗證其實際值前,都要對其預設值先進行一次驗證,注意這裡只是驗證一次,發生在驗證第一個ConfigurationProperty的值之前。表現形式就好像靜態建構函式似的。
比如下面的ConfigurationSection和ConfigurationValidatorBase代碼:(代碼類比驗證年齡必須大於等於15歲,否則拋出異常)
//自訂ConfigurationSection
class AgeSection : ConfigurationSection
{
[ConfigurationProperty("age"), Age15Validator]
public int Age
{
get { return (int)this["age"]; }
set { this["age"] = value; }
}
}
//自訂驗證器
class Age15Validator : ConfigurationValidatorBase
{
public override bool CanValidate(Type type)
{
return type == typeof(Int32);
}
public override void Validate(object value)
{
int age = (int)value;
if (age < 15)
throw new ArgumentException("年齡必須大於等於15歲");
}
}
//驗證器Attribute
class Age15ValidatorAttribute : ConfigurationValidatorAttribute
{
public override ConfigurationValidatorBase ValidatorInstance
{
get
{
return new Age15Validator();
}
}
}
接著app.config定義一個合法的和一個非法的(Age小於15的AgeSection)ConfigurationSection
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="mysec1" type="Mgen.AgeSection, Mgen" />
<section name="mysec2" type="Mgen.AgeSection, Mgen" />
</configSections>
<mysec1 age="29" />
<mysec2 age="4" />
</configuration>
測試邏輯代碼:
try
{
var appconf = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var sec1 = appconf.GetSection("mysec1") as AgeSection;
if (sec1 != null)
Console.WriteLine(sec1.Age);
var sec2 = appconf.GetSection("mysec2") as AgeSection;
if (sec2 != null)
Console.WriteLine(sec2.Age);
}
catch (ConfigurationErrorsException ex)
{
Console.WriteLine(ex.Message);
}
這段代碼,最初想當然是先輸出29,因為mysec1會通過驗證,接著接到ConfigurationErrorsException,因為mysec2不會通過驗證的。可結果卻是連29都沒有輸出,直接顯示沒有通過驗證的錯誤資訊,檢查ConfigurationErrorsException的Line屬性竟然是0。
經過調試發現執行驗證器(本例中的Age15Validator類)的Validate函數次數是3,而不是最初所期望的2。這三次傳入的參數值分別是0,29,4。而這個0就是文章開頭提到的一類ConfigurationProperty的預設值,再次強調一下這個預設參數的驗證只調用一次,並且是限於任何實際ConfigurationProperty的真實值。
那麼,針對上述問題,解決方案是設定ConfigurationProperty的預設值並確保這個預設值能夠順利通過驗證器的驗證,比如上述程式我們就可以把AgeSection的Age屬性的預設值改成15.
[ConfigurationProperty("age", DefaultValue = 15), Age15Validator]
public int Age
{
get { return (int)this["age"]; }
set { this["age"] = value; }
}
這樣的話,程式就可以按要求運行了。
29
The value for the property 'age' is not valid. The error is: 年齡必須大於等於15
歲 (E:\My Documents\Visual Studio 2008\Projects\TTC\TTC\bin\Release\Mgen.exe.Con
fig line 9)
第一行輸出29(mysec1屬性通過驗證)
第二行輸出錯誤資訊並指出行數。(mysec2沒有通過驗證)