通過應用程序設置可以動態存儲和檢索應用程序的屬性設置和其他信息。應用程序設置是提高應用程序靈活性的必備手段之一。通常的應用程序設置可寫人數據庫、配置文件(如Web.Config的"appSettings"配置節)和Properties.Setting(WinForm、WPF客戶端可選)等。
本文要介紹的應用程序設置管理采用數據庫存儲的方式,實現了如下的目標:
1、支持多種數據庫,同時預留接口,用戶可對API進行靈活擴展,支持如XML等任意形式的存儲方式。
2、支持多應用程序、多客戶端(在C/S方式下特別有用)的應用程序設置管理,可方便地指定每個應用程序設置信息是否在各個應用程序、各個客戶端間共享。
3、API接口豐富、調用方便,支持泛型類型的應用程序設置信息,各個客戶端可隨意定義所要保存和加載的應用程序設置信息,服務器端可集中進行管理。
為實現一個滿足上述目標的應用程序設置API,主要采用了如下措施:
1、使用Provider模式,可把應用程序設置存儲在多種類型的數據庫中,用戶可通過實現具體的Provider,可以實現如XML等的存儲方式。如下是API的初始化方法:

2
3 public override void Initialize( string name, System.Collections.Specialized.NameValueCollection config)
4 {
5 // Validate arguments
6 if (config == null) throw new ArgumentNullException( " config ");
7 if ( string.IsNullOrEmpty(name)) name = " YbSettingProvider ";
8 if (String.IsNullOrEmpty(config[ " description "]))
9 {
10 config.Remove( " description ");
11 config.Add( " description ", " Yb setting provider ");
12 }
13 if (String.IsNullOrEmpty(config[ " applicationName "]))
14 {
15 config.Remove( " applicationName ");
16 config.Add( " applicationName ", " YbApp ");
17 }
18 if (String.IsNullOrEmpty(config[ " tableName "]))
19 {
20 config.Remove( " tableName ");
21 config.Add( " tableName ", " YbSettings ");
22 }
23
24 // Initialize base class
25 base.Initialize(name, config);
26
27 // Read connection string
28 this.ConnectionStringName = config.GetConfigValue( " connectionStringName ", null);
29 if ( string.IsNullOrWhiteSpace( this.ConnectionStringName))
30 throw new ConfigurationErrorsException(Resources.Required_connectionStringName_attribute_not_specified);
31 this.connectionStringSetting = ConfigurationManager.ConnectionStrings[ this.ConnectionStringName];
32 if ( this.connectionStringSetting == null)
33 throw new ConfigurationErrorsException( string.Format(Resources.Format_connection_string_was_not_found,
34 this.ConnectionStringName));
35 if ( string.IsNullOrEmpty( this.connectionStringSetting.ProviderName))
36 throw new ConfigurationErrorsException(
37 string.Format(
38 Resources.Format_connection_string_does_not_have_specified_the_providerName_attribute,
39 this.ConnectionStringName));
40
41 // 激發設置連接字符串前的事件處理程序,主要目的是解密連接字符串
42 ConnectionStringChangingEventArgs args =
43 RaiseConnectionStringChangingEvent(connectionStringSetting.ConnectionString);
44 if (args == null) throw new ProviderException(Resources.Connection_string_cannot_be_blank);
45 if (! this.connectionStringSetting.ConnectionString.Equals(args.ConnectionString))
46 {
47 this.connectionStringSetting =
48 new ConnectionStringSettings( this.ConnectionStringName, args.ConnectionString,
49 this.connectionStringSetting.ProviderName);
50 }
51 if ( string.IsNullOrEmpty( this.connectionStringSetting.ConnectionString))
52 throw new ProviderException(Resources.Connection_string_cannot_be_blank);
53
54 this.applicationName = config[ " applicationName "];
55
56 this.tableName = config[ " tableName "];
57
58 this.SiteName = config[ " siteName "];
59 SecUtility.CheckParameter( ref tableName, true, true, true, 255, " tableName ");
60 SecUtility.CheckParameter( ref applicationName, true, true, false, 255, " applicationName ");
61 SecUtility.CheckParameter( ref siteName, false, false, false, 255, " siteName ");
62 }
63
64 #endregion
從初始化方法中可以看出,可以在config文件中配置要存儲的數據庫表名(默認為YbSettings),應用程序名(ApplicationName)和客戶端站點名(SiteName),這個配置文件可以是Web.Config,也可以是App.Config,通過指定不同的應用程序名和客戶端站點名,可以隔離不同應用程序,同一應用程序不同客戶端間的應用程序設置信息。
2、應用程序設置類可以定義任意類型的屬性,非常靈活和方便,應用程序設置的保存和加載主要通過反射方式實現,具體的應用程序設置類可以像下面一樣:
{
public override bool AsShared
{
get { return false; }
}
[DisplayName( " 允許注冊 ")]
[System.ComponentModel.Description( " True:允許注冊,False:不允許注冊 ")]
[DefaultValue( true)]
public bool AllowRegister { get; set; }
public int MaxNumber { get; set; }
[DefaultValue(10d)]
public double MaxWidth { get; set; }
[DefaultValue(20d)]
public double MaxHeight { get; set; }
}
在上述的應用程序設置類的定義中,可以對每個屬性設置“DisplayName”特性和“Description”特性,這些信息將在反射時自動保存至數據庫中,主要目的是方便后台對單個屬性項進行管理;同時還可以設置“DefaultValue”特性,這樣如果數據庫中不存在該設置項將自動加載為指定的默認值,是不是非常方便和靈活!!!也可定義AsShared屬性指明該應用程序設置類的信息是否在同一應用程序多個客戶端或站點間進行共享。
具體的應用程序設置加載就方便多了,只需如下一條語句就可加載指定的類中定義的多個屬性對應的設置信息:
SettingApi.LoadSettings<ClientSetting>();
具體的保存也非常方便,也僅需一條語句即可:
SettingApi.SaveSettings(clientSetting);
具體到實現原理上,應用程序設置API將把上述設置信息類的每個屬性及其值按規則單獨保存至數據庫的一條記錄中,具體保存的實現方法使用了反射,代碼如下:

2 {
3 Initialize();
4
5 string siteName = string.Empty;
6 if (!settings.AsShared)
7 siteName = SiteName;
8 foreach ( var prop in typeof(T).GetProperties())
9 {
10 // get properties we can read and write to
11 if (!prop.CanRead || !prop.CanWrite)
12 continue;
13
14 if (!CommonHelper.GetCustomTypeConverter(prop.PropertyType).CanConvertFrom( typeof( string)))
15 continue;
16
17 string key = typeof(T).Name + " . " + prop.Name;
18
19 string displayName = prop.Name;
20 var displayNameAttrs = prop.GetCustomAttributes( typeof(DisplayNameAttribute), false);
21 if (displayNameAttrs.Length > 0)
22 {
23 DisplayNameAttribute attr = displayNameAttrs[ 0] as DisplayNameAttribute;
24 if (attr != null && ! string.IsNullOrWhiteSpace(attr.DisplayName))
25 displayName = attr.DisplayName;
26 }
27 string description = string.Empty;
28 var desAttrs = prop.GetCustomAttributes( typeof(DescriptionAttribute), false);
29 if (desAttrs.Length > 0)
30 {
31 DescriptionAttribute attr = desAttrs[ 0] as DescriptionAttribute;
32 if (attr != null && ! string.IsNullOrWhiteSpace(attr.Description))
33 description = attr.Description;
34 }
35
36 dynamic value = prop.GetValue(settings, null);
37 if (value != null)
38 SetSetting(key, value, displayName: displayName, description: description, siteName: siteName);
39 else
40 SetSetting(key, "", displayName, description, siteName);
41 }
42 }
本應用程序設置在配置文件中的配置方式如下:
< setting defaultProvider ="YbSettingProvider" >
< providers >
< add name ="YbSettingProvider" connectionStringName ="AdMisDb" applicationName ="YbApplication" siteName ="YbTestSite" type ="Yb.Data.Provider.YbSettingProvider,Yb.Data.Provider" ></ add >
</ providers >
</ setting >
</ yb.data >
附最新發布 YbRapidSolution for MVC Demo 地址:http://mvcdemo.yellbuy.com/
YbSoftwareFactory 2.4正式發布,提供下載地址:http://download.yellbuy.com/ybsoftwarefactory/Yb.SoftwareFactory_V2_Release.rar
下一章將我們將討論 Web API 的安全