zoukankan      html  css  js  c++  java
  • BlogEngine.Net架构与源代码分析系列part4:Blog全局设置——BlogSettings

    在这篇文章中我们将对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. 1/**//// <summary>
    2. 2/// Public event used to indicate in settings have been changed.
    3. 3/// </summary>
    4. 4public static event EventHandler<EventArgs> Changed;
    5. 5/**//// <summary>
    6. 6/// Private member to hold singleton instance.
    7. 7/// </summary>
    8. 8private static BlogSettings blogSettingsSingleton;
    9. 9
    10. 10Instance#region Instance
    11. 11/**//// <summary>
    12. 12/// Gets the singleton instance of the <see cref="BlogSettings"/> class.
    13. 13/// </summary>
    14. 14/// <value>A singleton instance of the <see cref="BlogSettings"/> class.</value>
    15. 15/// <remarks></remarks>
    16. 16public static BlogSettings Instance
    17. 17{
    18. 18    get
    19. 19    {
    20. 20        if (blogSettingsSingleton == null)
    21. 21        {
    22. 22            blogSettingsSingleton = new BlogSettings();
    23. 23        }
    24. 24        return blogSettingsSingleton;
    25. 25    }
    26. 26}
    27. 27#endregion
    复制代码

    从这里我们就可以知道为什么对于数据源的直接修改不能在BlogEngine.Net的运行系统中体现的原因了。

        BlogSettings在对象构造时执行了一个Load方法来加载所有数据存储中的配置信息,这个加载过程应用到了.Net反射技术,找到数据存储中与对象属性相同名称的配置项并将其值强制转换以后付给属性,当然这里的数据访问是通过我的第三篇文章中讲述的BlogService调用获得。同理修改配置是通过Save将数据保存回数据存储,也是使用反射完成。

    1.   1BlogSettings()#region BlogSettings()
    2.   2/**//// <summary>
    3.   3/// Initializes a new instance of the <see cref="BlogSettings"/> class.
    4.   4/// </summary>
    5.   5private BlogSettings()
    6.   6{
    7.   7    Load();
    8.   8}
    9.   9#endregion
    10. 10
    11. 11Load()#region Load()
    12. 12/**//// <summary>
    13. 13/// Initializes the singleton instance of the <see cref="BlogSettings"/> class.
    14. 14/// </summary>
    15. 15private void Load()
    16. 16{
    17. 17    Type settingsType = this.GetType();
    18. 18
    19. 19    //------------------------------------------------------------
    20. 20    //    Enumerate through individual settings nodes
    21. 21    //------------------------------------------------------------
    22. 22    System.Collections.Specialized.StringDictionary dic = Providers.BlogService.LoadSettings();
    23. 23       
    24. 24    foreach (string key in dic.Keys)
    25. 25    {
    26. 26        //------------------------------------------------------------
    27. 27        //    Extract the setting's name/value pair
    28. 28        //------------------------------------------------------------
    29. 29        string name = key;
    30. 30        string value = dic[key];
    31. 31
    32. 32        //------------------------------------------------------------
    33. 33        //    Enumerate through public properties of this instance
    34. 34        //------------------------------------------------------------
    35. 35        foreach (PropertyInfo propertyInformation in settingsType.GetProperties())
    36. 36        {
    37. 37            //------------------------------------------------------------
    38. 38            //    Determine if configured setting matches current setting based on name
    39. 39            //------------------------------------------------------------
    40. 40            if (propertyInformation.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
    41. 41            {
    42. 42                //------------------------------------------------------------
    43. 43                //    Attempt to apply configured setting
    44. 44                //------------------------------------------------------------
    45. 45                try
    46. 46                {
    47. 47                    propertyInformation.SetValue(this, Convert.ChangeType(value, propertyInformation.PropertyType, CultureInfo.CurrentCulture), null);
    48. 48                }
    49. 49                catch
    50. 50                {
    51. 51                    // TODO: Log exception to a common logging framework?
    52. 52                }
    53. 53                break;
    54. 54            }
    55. 55        }
    56. 56    }
    57. 57        storageLocation = Providers.BlogService.GetStorageLocation();
    58. 58}
    59. 59#endregion
    60. 60
    61. 61Save()#region Save()
    62. 62/**//// <summary>
    63. 63/// Saves the settings to disk.
    64. 64/// </summary>
    65. 65public void Save()
    66. 66{
    67. 67    System.Collections.Specialized.StringDictionary dic = new System.Collections.Specialized.StringDictionary();
    68. 68    Type settingsType = this.GetType();
    69. 69
    70. 70    //------------------------------------------------------------
    71. 71    //    Enumerate through settings properties
    72. 72    //------------------------------------------------------------
    73. 73    foreach (PropertyInfo propertyInformation in settingsType.GetProperties())
    74. 74    {
    75. 75        try
    76. 76        {
    77. 77            if (propertyInformation.Name != "Instance")
    78. 78            {
    79. 79                //------------------------------------------------------------
    80. 80                //    Extract property value and its string representation
    81. 81                //------------------------------------------------------------
    82. 82                object propertyValue = propertyInformation.GetValue(this, null);
    83. 83                string valueAsString = propertyValue.ToString();
    84. 84
    85. 85                //------------------------------------------------------------
    86. 86                //    Format null/default property values as empty strings
    87. 87                //------------------------------------------------------------
    88. 88                if (propertyValue.Equals(null))
    89. 89                {
    90. 90                    valueAsString = String.Empty;
    91. 91                }
    92. 92                if (propertyValue.Equals(Int32.MinValue))
    93. 93                {
    94. 94                    valueAsString = String.Empty;
    95. 95                }
    96. 96                if (propertyValue.Equals(Single.MinValue))
    97. 97                {
    98. 98                    valueAsString = String.Empty;
    99. 99                }
    100. 100
    101. 101                //------------------------------------------------------------
    102. 102                //    Write property name/value pair
    103. 103                //------------------------------------------------------------
    104. 104                dic.Add(propertyInformation.Name, valueAsString);
    105. 105            }
    106. 106        }
    107. 107        catch { }
    108. 108    }
    109. 109
    110. 110    Providers.BlogService.SaveSettings(dic);
    111. 111    OnChanged();
    112. 112}
    113. 113#endregion
    复制代码

    客户端的使用方法(注意:这里所说的客户端是指BlogSettings使用者或调用者)

    1. 1 // Get Smtp Server
    2. 2 string server = BlogSettings.Instance.SmtpServer;
    3. 3
    4. 4 // Set Smtp Server
    5. 5 BlogSettings.Instance.SmtpServer = "HostName";
    6. 6 BlogSettings.Instance.Save();
    复制代码

    总结

        从BlogEngine.Net的全局配置部分我们可以学习到以下几点:
    1.单例模式是如何应用在实际项目中的。
    2.配置项的数据存取部分的实现有很好的参考价值,可以了解到.Net的反射给开发带来的方便。
    3.对于静态事件的使用(BlogEngine.Net中有很多例子)使得我们可以在外部做一些扩展,例如开发一个监控配置修改的跟踪系统。

        好的设计要经过不断的重构才可以达到。

  • 相关阅读:
    同一个硬盘安装win10+ubuntu双系统
    Bundle
    layout_weight属性
    Java反射机制
    Android——Widget实现
    Android——悬浮窗+侧边弹框+淡入淡出+背景shape+SeekBar调节手机亮度
    Android权限总结
    Android——窗口层控制WindowManager.LayoutParams.type
    Android——getSystemService
    Eclipse UML插件——AmaterasUML
  • 原文地址:https://www.cnblogs.com/encounter/p/2188814.html
Copyright © 2011-2022 走看看