如何分离web.config改进版本

      三年前我分享了如何分离web.config中的配置节,因为有些项目过大,造成N多配置节存在于web.config中,缺点如下:
      1:不容易管理,当你想查找一个配置节时,望着整页的code,不知所措,为此你只有ctrl+f来解决。
      2:部署时也及容易出错,部署人员需要按照你写的部署文档,一个一个加,即费时又容易出错,比如一不小心将其它节点给覆盖了诸如此类。
      3:在web.config中的配置节的修改会引起站点重启。
      4:访问配置节不够简单,容易出错。

      文章之前我提到过我们为了解决此种问题的解决方案,就是将配置节从web.config文件中分离出来,将配置节存入单独的文件中。具体的方案请参考前面的文章(如何分割web.config ),有很长一段时间没有使用了,最近在使用上发现在多项目中复用有一定问题,即每个项目都需要编写一段不短的代码,下面就是我对于它的优化过程,先看下原来的工作量:

      第一:Webconfig,这是框架里面的内容,这也是唯一得以复用的地方。它是一个入口,所有的配置文件引用都通过它,比如访问酒店的配置类,WebConfig.Hotel.HotelName。代码如下:    

ExpandedBlockStart.gif 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:一个配置文件路径的属性,它标识了此项目类所有配置文件的存放目录,可以在程序初始化时指定此属性。

     第二:自定义的配置文件类,比如我们可以添加一个数据访问的配置类。

 

ExpandedBlockStart.gif 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>中:

ExpandedBlockStart.gif 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方式来的舒服。

转载于:https://www.cnblogs.com/ASPNET2008/archive/2012/01/13/2322039.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值