YbSoftwareFactory 代码生成插件【十二】:超级灵活方便的应用程序设置管理API

    通过应用程序设置可以动态存储和检索应用程序的属性设置和其他信息。应用程序设置是提高应用程序灵活性的必备手段之一。通常的应用程序设置可写人数据库、配置文件(如Web.Config的"appSettings"配置节)和Properties.Setting(WinForm、WPF客户端可选)等。

    本文要介绍的应用程序设置管理采用数据库存储的方式,实现了如下的目标:

    1、支持多种数据库,同时预留接口,用户可对API进行灵活扩展,支持如XML等任意形式的存储方式。

    2、支持多应用程序、多客户端(在C/S方式下特别有用)的应用程序设置管理,可方便地指定每个应用程序设置信息是否在各个应用程序、各个客户端间共享。

    3、API接口丰富、调用方便,支持泛型类型的应用程序设置信息,各个客户端可随意定义所要保存和加载的应用程序设置信息,服务器端可集中进行管理。

    为实现一个满足上述目标的应用程序设置API,主要采用了如下措施:

    1、使用Provider模式,可把应用程序设置存储在多种类型的数据库中,用户可通过实现具体的Provider,可以实现如XML等的存储方式。如下是API的初始化方法:

Initialize
 1  #region Initialize
 2 
 3          public  override  void Initialize( string name, System.Collections.Specialized.NameValueCollection config)
 4         {
 5              //  Validate arguments
 6               if (config ==  nullthrow  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 ==  nullthrow  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,  truetruetrue255" tableName ");
60             SecUtility.CheckParameter( ref applicationName,  truetruefalse255" applicationName ");
61             SecUtility.CheckParameter( ref siteName,  falsefalsefalse255" siteName ");
62         }
63 
64          #endregion

    从初始化方法中可以看出,可以在config文件中配置要存储的数据库表名(默认为YbSettings),应用程序名(ApplicationName)和客户端站点名(SiteName),这个配置文件可以是Web.Config,也可以是App.Config,通过指定不同的应用程序名和客户端站点名,可以隔离不同应用程序,同一应用程序不同客户端间的应用程序设置信息。

    2、应用程序设置类可以定义任意类型的属性,非常灵活和方便,应用程序设置的保存和加载主要通过反射方式实现,具体的应用程序设置类可以像下面一样:

public  class ClientSetting : BaseSettings
    {
         public  override  bool AsShared
        {
             get {  return  false; }
        }

        [DisplayName( " 允许注册 ")]
        [System.ComponentModel.Description( " True:允许注册,False:不允许注册 ")]
        [DefaultValue( true)]
         public  bool AllowRegister {  getset; }

         public  int MaxNumber {  getset; }

        [DefaultValue(10d)]
         public  double MaxWidth {  getset; }

        [DefaultValue(20d)]
         public  double MaxHeight {  getset; }
    }

    在上述的应用程序设置类的定义中,可以对每个属性设置“DisplayName”特性和“Description”特性,这些信息将在反射时自动保存至数据库中,主要目的是方便后台对单个属性项进行管理;同时还可以设置“DefaultValue”特性,这样如果数据库中不存在该设置项将自动加载为指定的默认值,是不是非常方便和灵活!!!也可定义AsShared属性指明该应用程序设置类的信息是否在同一应用程序多个客户端或站点间进行共享。

    具体的应用程序设置加载就方便多了,只需如下一条语句就可加载指定的类中定义的多个属性对应的设置信息:

    SettingApi.LoadSettings<ClientSetting>();

    具体的保存也非常方便,也仅需一条语句即可:

    SettingApi.SaveSettings(clientSetting);

    具体到实现原理上,应用程序设置API将把上述设置信息类的每个属性及其值按规则单独保存至数据库的一条记录中,具体保存的实现方法使用了反射,代码如下:

SaveSettings
 1  public  static  void SaveSettings<T>(T settings)  where T : BaseSettings,  new()
 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[ 0as 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[ 0as 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         }

    本应用程序设置在配置文件中的配置方式如下:

   < yb.data >
     < 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 的安全

你可能感兴趣的:(refactor)