如何分離web.config改進版本


      三年前我分享了如何分離web.config中的配置節,因為有些項目過大,造成N多配置節存在於web.config中,缺點如下:
      1:不容易管理,當你想查找一個配置節時,望着整頁的code,不知所措,為此你只有ctrl+f來解決。
      2:部署時也及容易出錯,部署人員需要按照你寫的部署文檔,一個一個加,即費時又容易出錯,比如一不小心將其它節點給覆蓋了諸如此類。
      3:在web.config中的配置節的修改會引起站點重啟。
      4:訪問配置節不夠簡單,容易出錯。

      文章之前我提到過我們為了解決此種問題的解決方案,就是將配置節從web.config文件中分離出來,將配置節存入單獨的文件中。具體的方案請參考前面的文章(如何分割web.config ),有很長一段時間沒有使用了,最近在使用上發現在多項目中復用有一定問題,即每個項目都需要編寫一段不短的代碼,下面就是我對於它的優化過程,先看下原來的工作量:

      第一:Webconfig,這是框架里面的內容,這也是唯一得以復用的地方。它是一個入口,所有的配置文件引用都通過它,比如訪問酒店的配置類,WebConfig.Hotel.HotelName。代碼如下:    

View Code
public  partial   class WebConfig
    {
         ///   <summary>
        
///  啟動配置類
        
///   </summary>
        public  static  void OnStart( string configFilePath, FileUpdate fileUpdate)
        {
             #region  實現配置文件獨立
             // 第一次啟動需要執行委托方法更新配置類
            fileUpdate(configFilePath);
             // 啟動文件監視
            Log4netFileWatchHelper.StartWatching(fileUpdate, configFilePath);
             #endregion
        }
         ///   <summary>
        
///  Config/Web 文件夾的磁盤路徑
        
///   </summary>
        public  static  string ConfigFilePathRoot
       {
            get;
            set;
       }       
    }


       1:包含一個重要方法OnStart,可以對配置文件進行初始化,其實這個初始化也可以省略掉,因為完全可以將初始化配置類變成延遲加載模式。
       2:一個配置文件路徑的屬性,它標識了此項目類所有配置文件的存放目錄,可以在程序初始化時指定此屬性。

     第二:自定義的配置文件類,比如我們可以添加一個數據訪問的配置類。

 

View Code
 [Serializable ]
     public   class DataAccessConfig
    {   
         #region 需要序列化的配置文件屬性
         ///   <summary>
        
///  數據庫信息列表
        
///   </summary>
         public List<DataBase> DataBaseList {  getset; }
         #endregion

         #region 相對於Config文件夾的子文件路徑,不需要序列化.
         ///   <summary>
        
///  相對於Config文件夾的子文件路徑,不需要序列化.
        
///   </summary>
        [NonSerialized()]
         private  static  string m_SubFilePath =  @" DataAccessConfig.config ";
         ///   <summary>
        
///  子文件路徑(排除config文件夾路徑后的部分)
        
///   </summary>
         public  static  string SubFilePath
        {
             get {  return m_SubFilePath; }
             set { m_SubFilePath = value; }
        }
         #endregion
         public  static DataAccessConfig CreateInstance()
        {
            FileUpdate fileUpdate =  new FileUpdate(WebConfig.DataAccessConfigOnUpdate);
             string configFilePath = WebConfig.ConfigFilePathRoot + DataAccessConfig.SubFilePath;
             if (!File.Exists(configFilePath))
            {
                 return  null;
            }
            DataAccessConfig config = SerializationHelper.Load( typeof(DataAccessConfig), configFilePath)  as DataAccessConfig;
             // 啟動文件監視
            Log4netFileWatchHelper.StartWatching(fileUpdate, configFilePath);
             return config;
        }     
    }
   
     public  partial  class WebConfig
    {
         #region 第二步:為DataAccessConfig類添加入口
         ///   <summary>
        
///  屬性對應的私有變量
        
///   </summary>
         private  static DataAccessConfig m_DataAccessConfig =  null;
         ///   <summary>
        
///  屬性訪問器.通過WebConfig.SimpleFileDemoConfig可以訪問此類.
        
///   </summary>
         public  static DataAccessConfig DataAccessConfig
        {
             get
            {
                 if (m_DataAccessConfig ==  null)
                    Interlocked.CompareExchange<DataAccessConfig>( ref m_DataAccessConfig,
                        DataAccessConfig.CreateInstance(),  null);
                 return m_DataAccessConfig;
            }
        }
         #endregion

         #region 第三步:為DataAccessConfig類添加更新函數
         ///   <summary>
        
///  更新函數
        
///   </summary>
        
///   <param name="status"></param>
         public  static  void DataAccessConfigOnUpdate( object status)
        {
             lock (WebConfig.DataAccessConfig)
            {
                 try
                {
                    m_DataAccessConfig = DataAccessConfig.CreateInstance();
                }
                 catch (Exception ex)
                {
                     throw ex;
                }
            }
        }
         #endregion
    }

 

       這段代碼就是我們要實現的部分,不能復用,總覺的需要改進一下,問題分析:
       1:由於需要采用靜態調用方式,為此要想通過WebConfig的靜態屬性調用,就需要在WebConfig類中增加自定義配置類的屬性,比如我們增加一個Hotel相關的配置類,而要想WebConfig.Hotel,就需要增加一個靜態屬性方式實現。這里可以稍微修改下,即最后在配置自定義配置類時只編寫自定義配置類,而不用去編寫WebConfig類。
       2:自定義配置類中的CreateInstance,也要考慮復用。

       原則就是自定義的配置類不關心如何讀取配置文件,只關心自己的配置屬性即可。
       
       改善后的版本:
       1:針對WebConfig.自定義類方式。這里我修改的方法也不是最好的,用起來沒有修改前的順暢,但代碼確實精簡了。思路就是在WebConfig類中生成一個泛型配置類。
       

public  partial  class WebConfig<T> :WebConfig  where T: class

 

       這里新增了WebConfig的泛型版本,而將WebConfig提取成基類,WebConfig類中包含一個屬性,即配置文件所在文件夾路徑。
      

  ///   <summary>
        
///  Config/Web 文件夾的磁盤路徑
        
///   </summary>
         public  static  string ConfigFilePathRoot
        {
             get;
             set;
        }

 

        WebConfig<T>主要目的是為了生成T類型的配置類,這里將原本在自定義配置類中的代碼提取到WebConfig<T>中:

View Code
          ///   <summary>
        
///  屬性對應的私有變量
        
///   </summary>
         private  static T m_DataAccessConfig ;
         ///   <summary>
        
///  屬性訪問器.通過WebConfig.SimpleFileDemoConfig可以訪問此類.
        
///   </summary>
         public  static T DataAccessConfig
        {
             get
            {
                 if (m_DataAccessConfig ==  null)
                    Interlocked.CompareExchange<T>( ref m_DataAccessConfig,
                        CreateInstance(),  null );
                 return m_DataAccessConfig;
            }
        }        
          ///   <summary>
        
///  更新函數
        
///   </summary>
        
///   <param name="status"></param>
         public  static  void DataAccessConfigOnUpdate( object status)
        {
             lock (WebConfig<T>.DataAccessConfig)
            {
                 try
                {
                    m_DataAccessConfig = CreateInstance();
                }
                 catch (Exception ex)
                {
                     throw ex;
                }
            }
        }

    
        2:將自定義配置類生成實例的方法也進行封裝。
         

private  static T CreateInstance()
        {
            SubFilePath =  typeof(T).Name+ " .config ";
             string configFilePath = WebConfig<T>.ConfigFilePathRoot + SubFilePath;
             if (!File.Exists(configFilePath))
            {
                 return  null;
            }
            T config = SerializationHelper.Load( typeof(T), configFilePath)  as T;
             // 啟動文件監視
            FileWatch(configFilePath);
             return config;            

        }

        
        有了上面的提取封裝,下面就是改版后的自定義類了,到目前為止,我們編寫一個自定義配置類的成本已經非常低了:
        

[Serializable]
     public  class MyConfig : WebConfig<DataAccessConfig>
    {
         #region 需要序列化的配置文件屬性
         public  string ExpenseTemplateFile {  getset; }
         public  bool Switch {  getset; }
         #endregion      
    }

 

       最后我們添加一個配置文件,名稱和自定義配置類保持一致。
      

  <?xml version= " 1.0 " encoding= " utf-8 " ?>
<MyConfig>
  <ExpenseTemplateFile>ssssss3</ExpenseTemplateFile>
  <Switch> false</Switch>
</MyConfig>

    
      客戶端調用方式:   

WebConfig<MyConfig>.DataAccessConfig.Switch

      

       雖然本次改版並不完美,但在多個項目中利用時還是起到了很大的作用,編寫簡單,調用方便,唯一不滿意的就是需要這樣寫:WebConfig<MyConfig>,沒有以前的WebConfig.MyConfig方式來的舒服。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM