.net 序列化通用的方法
1//是否写日志
2#define txtLogAll
3
4using System;
5using System.Web;
6using System.Xml.Serialization;
7using System.IO;
8using System.Runtime.Serialization;
9using System.Runtime.Serialization.Formatters.Soap;
10using System.Runtime.Serialization.Formatters.Binary;
11using System.Web.Caching;
12using System.Threading;
13using tjb.Utility.Caching;
14using System.Xml;
15using System.Text;
16
17
18namespace tjb.Utility.Config
19{
20
21 文件序列化的类型
42
43 /// <summary>
44 /// 序列化基类 by Tjb 2007/06
45 /// T 类型不能创建多态的多个实例
46 /// 优化和修正,增加配置文件备份 2008/9/18
47 /// 修改:获取实例时加锁
48 /// 修改:
49 /// SaveAs(T Tobj, string FileFullName, bool BackupOnError) 方法增加线程锁定。防止多线程冲突 2008/10/24
50 /// </summary>
51 /// <typeparam name="T">T 必须有无参数的构造函数</typeparam>
52 [Serializable]
53 public abstract class IConfig<T> where T : IConfig<T>, new()
54 {
55
56 #region Exceptions
57 private Exception __ConfigException;
58 /// <summary>
59 /// 读取或保存时发生的错误
60 /// </summary>
61 [XmlIgnore, SoapIgnore]
62 public Exception Exception
63 {
64 get
65 {
66 return __ConfigException;
67 }
68 private set
69 {
70 if (value != null)
71 {
72 HasError = true;
73 __ConfigException = value;
74#if txtLogAll
75 Log.WriteLog(value);
76#endif
77 }
78 }
79 }
80 private bool __HasError = false;
81 /// <summary>
82 /// 获取一个值 指示读取或者保存时是否发生错误
83 /// 如果当前错误被获取后,此标志将被置为false
84 /// </summary>
85 [XmlIgnore, SoapIgnore]
86 public bool HasError
87 {
88 get { return __HasError; }
89 private set { __HasError = value; }
90 }
91 #endregion
92
93 #region 序列化类型 可重写
94
95 private Formatter _CurrentFormatter = Formatter.Xml;
96 /// <summary>
97 /// 序列化的方式
98 /// </summary>
99 [XmlIgnore]
100 protected virtual Formatter CurrentFormatter
101 {
102 get
103 {
104 return _CurrentFormatter;
105 }
106 set
107 {
108 _CurrentFormatter = value;
109 }
110 }
111
112 #endregion
113
114 #region 获取单个实例
115
116 /// <summary>
117 /// 获取Cache中缓存T的key
118 /// </summary>
119 public static string CacheKEY
120 {
121 get
122 {
123 // return typeof(T).GUID.ToString("N");
124 return typeof(T).FullName;
125 }
126 }
127 /// <summary>
128 /// 从缓存(缓存KEY为T的命空间加类名)获取当前类的实例,如果缓存不存在则读取文件(ConfigFileFullName), 并缓存。
129 /// </summary>
130 public static T Instance
131 {
132 get
133 {
134 T c = CacheUtility.Get<T>(CacheKEY);
135 if (c == null)
136 {
137 //这中方式无异于不加锁
138 //object Monitor = new object();
139 //lock (Monitor)
140 lock (typeof(T))
141 {
142 c = CacheUtility.Get<T>(CacheKEY);
143 if (c == null)
144 {
145 c = new T().Read();
146#if DEBUG
147 CacheUtility.SetSlidingExpiration(CacheKEY, c, c.ConfigFileFullName, 7, CacheItemPriority.NotRemovable, new CacheItemRemovedCallback(CallR));
148#else
149 CacheUtility.SetSlidingExpiration(CacheKEY, c, c.ConfigFileFullName, 7, CacheItemPriority.NotRemovable, null);
150#endif
151 }
152 }
153 }
154 return c;
155 }
156 }
157
158 #endregion
159
160 #region Caching..
161
162 /// <summary>
163 /// 从ConfigFileName指定文件以CurrentSerializeType读取实例,如果存在缓存则移除并重新进行缓存
164 /// 如果不存在则以InitConfig初始化类,创建并保存文件
165 /// </summary>
166 /// <returns></returns>
167 protected T ResetCacheAndRead()
168 {
169 ResetCache();
170 return Read();
171 }
172 /// <summary>
173 /// 移除CacheKEY 缓存
174 /// </summary>
175 public void ResetCache()
176 {
177 HttpRuntime.Cache.Remove(CacheKEY);
178 }
179 #endregion
180
181 #region 获取
182
183 /// <summary>
184 /// 读取缓存中的实例如果不存在则
185 /// 从ConfigFileName指定文件以CurrentSerializeType读取实例
186 /// 如果不存在则以InitConfig初始化类,创建并保存文件
187 /// </summary>
188 /// <returns></returns>
189 virtual protected T Read()
190 {
191 return Read(ConfigFileFullName, true, CurrentFormatter);
192 }
193
194 /// <summary>
195 /// 从ConfigFileName指定文件以CurrentSerializeType读取实例
196 /// 如果不存在则以InitConfig初始化类,创建并保存文件
197 /// </summary>
198 /// <param name="configFileFullName">缓存文件绝对路径</param>
199 /// <param name="serializeType"></param>
200 /// <param name="BackupOnError">读取错误时是否备份</param>
201 /// <returns></returns>
202 protected T Read(string configFileFullName, bool BackupOnError, Formatter serializeType)
203 {
204 T t = CacheUtility.Get<T>(CacheKEY);
205 if (t != null)
206 return t;
207 FileInfo fi = new FileInfo(configFileFullName);
208 if (fi.Exists)
209 {
210
211 FileStream fs = null;
212 try
213 {
214 open the stream
236
237 if (fs != null)
238 fs.Close();
239 }
240 catch (Exception ex)
241 {
242 if (fs != null)
243 fs.Close();
244 t = CustomizingInit();
245
246 读取失败 进行备份 防止以后使用默认配置覆盖当前数据
262
263 t.Exception = new Exception("读取配置文件时发生错误!将返回CustomizingInit()方法的实例,默认为 new T()!", ex);
264 }
265 finally
266 {
267
268 }
269 }
270 else
271 {
272 t = CustomizingInit();
273
274 //不存在的同一文件不能读多次
275 //防止在CustomizingInit()方法中调用Read(string configFileName, SerializeType serializeType) 造成死循环
276 string ProtectedKEY = Thread.CurrentThread.ManagedThreadId + fi.FullName + "init";
277 if (CacheUtility.GetAnyType<bool>(ProtectedKEY) == false)
278 {
279 CacheUtility.SetAbsoluteExpiration(ProtectedKEY, true, null, 0.02);
280 }
281 else
282 {
283 CacheUtility.Remove(ProtectedKEY);
284 throw new Exception("'" + fi.FullName + "' 文件不存在!读取过于频繁。导致此保护异常发生。");
285 }
286 t.Exception = new Exception("配置文件:'" + fi.FullName + "' 不存在!默认返回CustomizingInit()方法返回的实例。");
287 }
288 if (t == null)
289 t.Exception = new Exception("发生错误,请检查初始化配置方法 CustomizingInit() 未返回的配置实例不能为空,或者系统中存在缓存 key :" + CacheKEY);
290 return t;
291 }
292
293#if DEBUG
294 private static void CallR(string key, object obj, CacheItemRemovedReason re)
295 {
296#if txtLogAll
297 Log.WriteLog(key + "::::" + re.ToString());
298#endif
299 }
300#endif
301
302 #endregion
303
304 保存
446
447 删除配置文件
476
477 #region 抽象成员
478 /// <summary>
479 /// 返回派生类的当前实例
480 /// protected override T Current
481 /// {
482 /// get
483 /// {
484 /// return this;
485 /// }
486 /// }
487 /// </summary>
488 protected abstract T Current
489 {
490 get;
491 }
492 /// <summary>
493 /// 自定义初始化配置类
494 /// 获取 T 的配置实例时,如果配置文件不存在或者读取失败时返回此实例
495 /// 重写中一般读取备份的配置文件,必须保证备份配置文件存在,否则发生异常。
496 /// 默认返回 new T();
497 /// </summary>
498 /// <returns></returns>
499 protected virtual T CustomizingInit()
500 {
501 return Current;
502 }
503 /// <summary>
504 /// 配置文件名
505 /// <c>配置文件名</c>
506 /// <example>
507 /// 配置文件名
508 /// </example>
509 /// </summary>
510 private string ___file = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Config/" + typeof(T).Name + ".cfg");
511 /// <summary>
512 /// 配置文件全路径名
513 /// 默认:winform 在应用程序目录;web应用程序默认bin目录。
514 /// </summary>
515 [XmlIgnore]
516 public virtual string ConfigFileFullName
517 {
518 get
519 {
520 return ___file;
521 }
522 set
523 {
524 ___file = value;
525 }
526 }
527 #endregion
528 }
529}