BlogEngine.Net架构与源代码分析系列part4:Blog全局设置——BlogSettings
2011-03-26 21:50
531 查看
在这篇文章中我们将对BlogEngine.Net的全局配置进行一下分析与探讨。关于配置这一部分单独拿出来做一篇文章实在有些牵强,但是我总觉得这个配置部分比较独立,而且BlogEngine.Net的设计和实现都有很多可以参考的地方。
在一个企业级应用系统中,对一些系统全局参数进行配置是必不可少的,那么我们是怎么处理这些配置的呢?
一般都有以下三步:
1.在业务模块开发的过程中将一些可变的参量提取出来。
2.当所有业务模块开发完成时,将这些参量分类存储起来。
3.开发出相应的管理功能,允许用户对这些参量进行设置。
相信大多数开发者都是直接操作数据库中的数据,可能有些比较完善的系统会做出单独的页面来给用户管理使用,本质上也都是直接与数据库打交道,没有涉及太多的逻辑,比较直接。不过在BlogEngine.Net的架构模型上这种操作就失效了,我们不可以在BlogEngine.Net的数据库中修改数据而希望在它的运行系统中体现出来(除非重启应用),因为BlogEngine.Net的数据库只是完成数据存储功能,所有的业务逻辑都在BlogEngine.Core层由对象的状态维护来完成(可以参考我的第二篇文章)。有人可能会想可不可以进一步开发一种像Asp.Net中Cache那样对数据库表的依赖机制,我觉得这个问题要看需求,这种在BlogEngine.Net中似乎没有什么太多必要。
那么BlogEngine.Net的全局设置到底是怎么实现的呢?
在安装BlogEngine.Net以后进入后台管理中,我们会看到有很多分类的配置选项,包括主题,语言文化,时区等。这些配置的逻辑处理都是通过BlogEngine.Core中的一个类完成的,那就是BlogSettings。BlogSettings只是完成BlogEngine.Net的全局的配置处理,对于后文讲述的Widget的一些具体配置并不在这里完成,这主要是为了配置独立的目的,使得Widget可以独立开发。
BlogSettings与外界交互图(这个图使用画图程序弄的,大家先凑合着看吧):
附件: BlogSetting.jpg
在BlogSettings中除了各种配置项的对应属性以外,还有一个静态的Changed事件用来通知外部全局配置已经发生了改变,这样就可以写出更多扩展来。BlogSettings使用单例模式来实现(一个设计模式的很好的应用,全局配置具有系统唯一性)。
1/**//// <summary>
2/// Public event used to indicate in settings have been changed.
3/// </summary>
4public static event EventHandler<EventArgs> Changed;
5/**//// <summary>
6/// Private member to hold singleton instance.
7/// </summary>
8private static BlogSettings blogSettingsSingleton;
9
10Instance#region Instance
11/**//// <summary>
12/// Gets the singleton instance of the <see cref="BlogSettings"/> class.
13/// </summary>
14/// <value>A singleton instance of the <see cref="BlogSettings"/> class.</value>
15/// <remarks></remarks>
16public static BlogSettings Instance
17{
18 get
19 {
20 if (blogSettingsSingleton == null)
21 {
22 blogSettingsSingleton = new BlogSettings();
23 }
24 return blogSettingsSingleton;
25 }
26}
27#endregion
复制代码
从这里我们就可以知道为什么对于数据源的直接修改不能在BlogEngine.Net的运行系统中体现的原因了。
BlogSettings在对象构造时执行了一个Load方法来加载所有数据存储中的配置信息,这个加载过程应用到了.Net反射技术,找到数据存储中与对象属性相同名称的配置项并将其值强制转换以后付给属性,当然这里的数据访问是通过我的第三篇文章中讲述的BlogService调用获得。同理修改配置是通过Save将数据保存回数据存储,也是使用反射完成。
1BlogSettings()#region BlogSettings()
2/**//// <summary>
3/// Initializes a new instance of the <see cref="BlogSettings"/> class.
4/// </summary>
5private BlogSettings()
6{
7 Load();
8}
9#endregion
10
11Load()#region Load()
12/**//// <summary>
13/// Initializes the singleton instance of the <see cref="BlogSettings"/> class.
14/// </summary>
15private void Load()
16{
17 Type settingsType = this.GetType();
18
19 //------------------------------------------------------------
20 // Enumerate through individual settings nodes
21 //------------------------------------------------------------
22 System.Collections.Specialized.StringDictionary dic = Providers.BlogService.LoadSettings();
23
24 foreach (string key in dic.Keys)
25 {
26 //------------------------------------------------------------
27 // Extract the setting's name/value pair
28 //------------------------------------------------------------
29 string name = key;
30 string value = dic[key];
31
32 //------------------------------------------------------------
33 // Enumerate through public properties of this instance
34 //------------------------------------------------------------
35 foreach (PropertyInfo propertyInformation in settingsType.GetProperties())
36 {
37 //------------------------------------------------------------
38 // Determine if configured setting matches current setting based on name
39 //------------------------------------------------------------
40 if (propertyInformation.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
41 {
42 //------------------------------------------------------------
43 // Attempt to apply configured setting
44 //------------------------------------------------------------
45 try
46 {
47 propertyInformation.SetValue(this, Convert.ChangeType(value, propertyInformation.PropertyType, CultureInfo.CurrentCulture), null);
48 }
49 catch
50 {
51 // TODO: Log exception to a common logging framework?
52 }
53 break;
54 }
55 }
56 }
57 storageLocation = Providers.BlogService.GetStorageLocation();
58}
59#endregion
60
61Save()#region Save()
62/**//// <summary>
63/// Saves the settings to disk.
64/// </summary>
65public void Save()
66{
67 System.Collections.Specialized.StringDictionary dic = new System.Collections.Specialized.StringDictionary();
68 Type settingsType = this.GetType();
69
70 //------------------------------------------------------------
71 // Enumerate through settings properties
72 //------------------------------------------------------------
73 foreach (PropertyInfo propertyInformation in settingsType.GetProperties())
74 {
75 try
76 {
77 if (propertyInformation.Name != "Instance")
78 {
79 //------------------------------------------------------------
80 // Extract property value and its string representation
81 //------------------------------------------------------------
82 object propertyValue = propertyInformation.GetValue(this, null);
83 string valueAsString = propertyValue.ToString();
84
85 //------------------------------------------------------------
86 // Format null/default property values as empty strings
87 //------------------------------------------------------------
88 if (propertyValue.Equals(null))
89 {
90 valueAsString = String.Empty;
91 }
92 if (propertyValue.Equals(Int32.MinValue))
93 {
94 valueAsString = String.Empty;
95 }
96 if (propertyValue.Equals(Single.MinValue))
97 {
98 valueAsString = String.Empty;
99 }
100
101 //------------------------------------------------------------
102 // Write property name/value pair
103 //------------------------------------------------------------
104 dic.Add(propertyInformation.Name, valueAsString);
105 }
106 }
107 catch { }
108 }
109
110 Providers.BlogService.SaveSettings(dic);
111 OnChanged();
112}
113#endregion
复制代码
客户端的使用方法(注意:这里所说的客户端是指BlogSettings使用者或调用者)
1 // Get Smtp Server
2 string server = BlogSettings.Instance.SmtpServer;
3
4 // Set Smtp Server
5 BlogSettings.Instance.SmtpServer = "HostName";
6 BlogSettings.Instance.Save();
复制代码
总结
从BlogEngine.Net的全局配置部分我们可以学习到以下几点:
1.单例模式是如何应用在实际项目中的。
2.配置项的数据存取部分的实现有很好的参考价值,可以了解到.Net的反射给开发带来的方便。
3.对于静态事件的使用(BlogEngine.Net中有很多例子)使得我们可以在外部做一些扩展,例如开发一个监控配置修改的跟踪系统。
好的设计要经过不断的重构才可以达到。
在一个企业级应用系统中,对一些系统全局参数进行配置是必不可少的,那么我们是怎么处理这些配置的呢?
一般都有以下三步:
1.在业务模块开发的过程中将一些可变的参量提取出来。
2.当所有业务模块开发完成时,将这些参量分类存储起来。
3.开发出相应的管理功能,允许用户对这些参量进行设置。
相信大多数开发者都是直接操作数据库中的数据,可能有些比较完善的系统会做出单独的页面来给用户管理使用,本质上也都是直接与数据库打交道,没有涉及太多的逻辑,比较直接。不过在BlogEngine.Net的架构模型上这种操作就失效了,我们不可以在BlogEngine.Net的数据库中修改数据而希望在它的运行系统中体现出来(除非重启应用),因为BlogEngine.Net的数据库只是完成数据存储功能,所有的业务逻辑都在BlogEngine.Core层由对象的状态维护来完成(可以参考我的第二篇文章)。有人可能会想可不可以进一步开发一种像Asp.Net中Cache那样对数据库表的依赖机制,我觉得这个问题要看需求,这种在BlogEngine.Net中似乎没有什么太多必要。
那么BlogEngine.Net的全局设置到底是怎么实现的呢?
在安装BlogEngine.Net以后进入后台管理中,我们会看到有很多分类的配置选项,包括主题,语言文化,时区等。这些配置的逻辑处理都是通过BlogEngine.Core中的一个类完成的,那就是BlogSettings。BlogSettings只是完成BlogEngine.Net的全局的配置处理,对于后文讲述的Widget的一些具体配置并不在这里完成,这主要是为了配置独立的目的,使得Widget可以独立开发。
BlogSettings与外界交互图(这个图使用画图程序弄的,大家先凑合着看吧):
附件: BlogSetting.jpg
在BlogSettings中除了各种配置项的对应属性以外,还有一个静态的Changed事件用来通知外部全局配置已经发生了改变,这样就可以写出更多扩展来。BlogSettings使用单例模式来实现(一个设计模式的很好的应用,全局配置具有系统唯一性)。
1/**//// <summary>
2/// Public event used to indicate in settings have been changed.
3/// </summary>
4public static event EventHandler<EventArgs> Changed;
5/**//// <summary>
6/// Private member to hold singleton instance.
7/// </summary>
8private static BlogSettings blogSettingsSingleton;
9
10Instance#region Instance
11/**//// <summary>
12/// Gets the singleton instance of the <see cref="BlogSettings"/> class.
13/// </summary>
14/// <value>A singleton instance of the <see cref="BlogSettings"/> class.</value>
15/// <remarks></remarks>
16public static BlogSettings Instance
17{
18 get
19 {
20 if (blogSettingsSingleton == null)
21 {
22 blogSettingsSingleton = new BlogSettings();
23 }
24 return blogSettingsSingleton;
25 }
26}
27#endregion
复制代码
从这里我们就可以知道为什么对于数据源的直接修改不能在BlogEngine.Net的运行系统中体现的原因了。
BlogSettings在对象构造时执行了一个Load方法来加载所有数据存储中的配置信息,这个加载过程应用到了.Net反射技术,找到数据存储中与对象属性相同名称的配置项并将其值强制转换以后付给属性,当然这里的数据访问是通过我的第三篇文章中讲述的BlogService调用获得。同理修改配置是通过Save将数据保存回数据存储,也是使用反射完成。
1BlogSettings()#region BlogSettings()
2/**//// <summary>
3/// Initializes a new instance of the <see cref="BlogSettings"/> class.
4/// </summary>
5private BlogSettings()
6{
7 Load();
8}
9#endregion
10
11Load()#region Load()
12/**//// <summary>
13/// Initializes the singleton instance of the <see cref="BlogSettings"/> class.
14/// </summary>
15private void Load()
16{
17 Type settingsType = this.GetType();
18
19 //------------------------------------------------------------
20 // Enumerate through individual settings nodes
21 //------------------------------------------------------------
22 System.Collections.Specialized.StringDictionary dic = Providers.BlogService.LoadSettings();
23
24 foreach (string key in dic.Keys)
25 {
26 //------------------------------------------------------------
27 // Extract the setting's name/value pair
28 //------------------------------------------------------------
29 string name = key;
30 string value = dic[key];
31
32 //------------------------------------------------------------
33 // Enumerate through public properties of this instance
34 //------------------------------------------------------------
35 foreach (PropertyInfo propertyInformation in settingsType.GetProperties())
36 {
37 //------------------------------------------------------------
38 // Determine if configured setting matches current setting based on name
39 //------------------------------------------------------------
40 if (propertyInformation.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
41 {
42 //------------------------------------------------------------
43 // Attempt to apply configured setting
44 //------------------------------------------------------------
45 try
46 {
47 propertyInformation.SetValue(this, Convert.ChangeType(value, propertyInformation.PropertyType, CultureInfo.CurrentCulture), null);
48 }
49 catch
50 {
51 // TODO: Log exception to a common logging framework?
52 }
53 break;
54 }
55 }
56 }
57 storageLocation = Providers.BlogService.GetStorageLocation();
58}
59#endregion
60
61Save()#region Save()
62/**//// <summary>
63/// Saves the settings to disk.
64/// </summary>
65public void Save()
66{
67 System.Collections.Specialized.StringDictionary dic = new System.Collections.Specialized.StringDictionary();
68 Type settingsType = this.GetType();
69
70 //------------------------------------------------------------
71 // Enumerate through settings properties
72 //------------------------------------------------------------
73 foreach (PropertyInfo propertyInformation in settingsType.GetProperties())
74 {
75 try
76 {
77 if (propertyInformation.Name != "Instance")
78 {
79 //------------------------------------------------------------
80 // Extract property value and its string representation
81 //------------------------------------------------------------
82 object propertyValue = propertyInformation.GetValue(this, null);
83 string valueAsString = propertyValue.ToString();
84
85 //------------------------------------------------------------
86 // Format null/default property values as empty strings
87 //------------------------------------------------------------
88 if (propertyValue.Equals(null))
89 {
90 valueAsString = String.Empty;
91 }
92 if (propertyValue.Equals(Int32.MinValue))
93 {
94 valueAsString = String.Empty;
95 }
96 if (propertyValue.Equals(Single.MinValue))
97 {
98 valueAsString = String.Empty;
99 }
100
101 //------------------------------------------------------------
102 // Write property name/value pair
103 //------------------------------------------------------------
104 dic.Add(propertyInformation.Name, valueAsString);
105 }
106 }
107 catch { }
108 }
109
110 Providers.BlogService.SaveSettings(dic);
111 OnChanged();
112}
113#endregion
复制代码
客户端的使用方法(注意:这里所说的客户端是指BlogSettings使用者或调用者)
1 // Get Smtp Server
2 string server = BlogSettings.Instance.SmtpServer;
3
4 // Set Smtp Server
5 BlogSettings.Instance.SmtpServer = "HostName";
6 BlogSettings.Instance.Save();
复制代码
总结
从BlogEngine.Net的全局配置部分我们可以学习到以下几点:
1.单例模式是如何应用在实际项目中的。
2.配置项的数据存取部分的实现有很好的参考价值,可以了解到.Net的反射给开发带来的方便。
3.对于静态事件的使用(BlogEngine.Net中有很多例子)使得我们可以在外部做一些扩展,例如开发一个监控配置修改的跟踪系统。
好的设计要经过不断的重构才可以达到。
相关文章推荐
- BlogEngine.Net架构与源代码分析系列part4:Blog全局设置——BlogSettings
- BlogEngine.Net架构与源代码分析系列part4:Blog全局设置——BlogSettings
- BlogEngine.Net架构与源代码分析系列part4:Blog全局设置——BlogSettings
- BlogEngine.Net架构与源代码分析系列part5:对象搜索——IPublishable与Search
- BlogEngine.Net架构与源代码分析系列part11:开发扩展(下)——自定义Theme
- BlogEngine.Net架构与源代码分析系列part5:对象搜索——IPublishable与Search
- BlogEngine.Net架构与源代码分析系列part5:对象搜索——IPublishable与Search
- BlogEngine.Net架构与源代码分析系列part13:实现分析(上)——HttpHandlers与HttpModules
- BlogEngine.Net架构与源代码分析系列part5:对象搜索——IPublishable与Search
- BlogEngine.Net架构与源代码分析系列part15:总结篇
- BlogEngine.Net架构与源代码分析系列part5:对象搜索——IPublishable与Search
- BlogEngine.Net架构与源代码分析系列part7:Web2.0特性——Pingback&Trackback
- BlogEngine.Net架构与源代码分析系列part9:开发扩展(上)——Extension与管理上的实现
- BlogEngine.Net架构与源代码分析系列part10:开发扩展(中)——Widget小工具
- BlogEngine.Net架构与源代码分析系列part14:实现分析(下)——网站页面上值得参考的部分
- BlogEngine.Net架构与源代码分析系列part12:页面共同的基类——BlogBasePage
- BlogEngine.Net架构与源代码分析系列part6:开放API——MetaWeblog与BlogImporter
- BlogEngine.Net架构与源代码分析系列part8:扩展——DataStore分析
- BlogEngine.Net架构与源代码分析系列(转载)
- BlogEngine.Net架构与源代码分析系列part2:业务对象——共同的父类BusinessBase