之前在WP7升级到WP8的时候遇到配置不兼容的问题
情景:之前只有一个WP7版本,现在需要发布WP8版本,让用户可以从原来的WP7版本升级到WP8版本
一般情况下从WP7升级到WP8没什么问题
但是在项目中升级到WP8的时候,原先在WP7下保存在IsolatedStorageSettings的数据都不出来,经过调试发现
1、IsolatedStorageSettings存放数据的隔离存储控件的"__ApplicationSettings"文件中,存放的格式如下 {"test":"TestData"}
<ArrayOfKeyValueOfstringanyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> <KeyValueOfstringanyType> <Key>test</Key> <Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:string">TestData</Value> </KeyValueOfstringanyType> </ArrayOfKeyValueOfstringanyType>
2、但是原来的项目中使用了友盟WP7版本,后来的项目中使用的是WP8版本,友盟会向"__ApplicationSettings"文件中写入数据,如下:
UmengSDK.Business.OnlineConfigManager+OnlineConfig, UmengAnalyticsWP7, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null <ArrayOfKeyValueOfstringanyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> <KeyValueOfstringanyType> <Key>test</Key> <Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:string">TestData</Value> </KeyValueOfstringanyType> <KeyValueOfstringanyType> <Key>device_id</Key> <Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:string">0BBB2DF41DD5688A25517F2968339DC0</Value> </KeyValueOfstringanyType> <KeyValueOfstringanyType> <Key>wp_device</Key> <Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:string">1C43AC07795C55C2ADA78B0DD5A79B3660A7D137</Value> </KeyValueOfstringanyType> <KeyValueOfstringanyType> <Key>config</Key> <Value xmlns:d3p1="http://schemas.datacontract.org/2004/07/UmengSDK.Business" i:type="d3p1:OnlineConfigManager.OnlineConfig"> <d3p1:Interval>30</d3p1:Interval> <d3p1:LastConfigTime>Wed Jul 02 00:43:35 CST 2014</d3p1:LastConfigTime> <d3p1:Policy>BATCH_AT_LAUNCH</d3p1:Policy> </Value> </KeyValueOfstringanyType> </ArrayOfKeyValueOfstringanyType>
3、而上面数据到了WP8上就不能正常读取原来存放的数据(如果在WP8项目中用WP7版的友盟则可以正常读取),导致原来存放的其他信息也读取不出来
4、下面试图自定义一个与 IsolatedStorageSettings 功能类似的类用于小数据的存取,避免第三方类库对"__ApplicationSettings"文件的修改导致一些兼容性问题
IsolatedStorageSettings 存放的是键值对,也就是字典模型,我们需要把Dictionary序列化到文件中,但是Dictionary不支持直接序列化,先对Dictionary进行扩展,让其支持序列化
using System; using System.Collections.Generic; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; namespace XTuOne.Common.Helpers { /// <summary> /// 可序列化的Dictionary /// </summary> [XmlRoot("Dictionary")] public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable { #region 构造函数,调用基类的构造函数 public SerializableDictionary() { } public SerializableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { } public SerializableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { } public SerializableDictionary(int capacity) : base(capacity) { } public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { } public SerializableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { } #endregion #region IXmlSerializable 接口的实现 public XmlSchema GetSchema() { throw new NotImplementedException(); } /// <summary> /// 从对象的XML表示形式生成该对象 /// </summary> /// <param name="reader"></param> public void ReadXml(XmlReader reader) { var keySerializer = new XmlSerializer(typeof (TKey)); var valueSerializer = new XmlSerializer(typeof (TValue)); bool wasEmpty = reader.IsEmptyElement; reader.Read(); if (wasEmpty) return; while (reader.NodeType != XmlNodeType.EndElement) { reader.ReadStartElement("Key"); TKey key = (TKey) keySerializer.Deserialize(reader); reader.ReadEndElement(); reader.ReadStartElement("Value"); TValue value = (TValue) valueSerializer.Deserialize(reader); reader.ReadEndElement(); this.Add(key, value); reader.MoveToContent(); } reader.ReadEndElement(); } /// <summary> /// 将对象转换为其XML表示形式 /// </summary> /// <param name="writer"></param> public void WriteXml(XmlWriter writer) { var keySerializer = new XmlSerializer(typeof (TKey)); var valueSerializer = new XmlSerializer(typeof (TValue)); foreach (TKey key in this.Keys) { writer.WriteStartElement("Key"); keySerializer.Serialize(writer, key); writer.WriteEndElement(); writer.WriteStartElement("Value"); TValue value = this[key]; valueSerializer.Serialize(writer, value); writer.WriteEndElement(); } } #endregion } }
5、使用系统的Xml序列化功能保存数据
using System; using System.IO; using System.IO.IsolatedStorage; using System.Windows; using System.Xml.Linq; using System.Xml.Serialization; namespace XTuOne.Common.Helpers { public class XmlHelper { private XmlHelper() { } /// <summary> /// 序列化对象到文件 /// </summary> /// <param name="file">文件路径:"/test.xml"</param> /// <param name="obj"></param> public static void Serialize<T>(string file, T obj) { using (var sf = IsolatedStorageFile.GetUserStoreForApplication()) { using (var fs = new IsolatedStorageFileStream(file, FileMode.OpenOrCreate, FileAccess.Write, sf)) { var serializer = new XmlSerializer(obj.GetType()); serializer.Serialize(fs, obj); } } } /// <summary> /// 反序列化文件到对象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="file">文件路径:"/test.xml"</param> public static T Deserialize<T>(string file) { using (var sf = IsolatedStorageFile.GetUserStoreForApplication()) { var serializer = new XmlSerializer(typeof(T)); using (var fs = sf.OpenFile(file, FileMode.Open, FileAccess.Read)) { return (T)serializer.Deserialize(fs); } } } /// <summary> /// 读取配置文件的信息 /// </summary> /// <param name="file">前面不加/</param> /// <param name="node">用.隔开(例如App.Version)</param> /// <param name="attribute"></param> public static string GetConfigValue(string file,string node, string attribute) { var configFile = Application.GetResourceStream(new Uri(file, UriKind.Relative)); return GetXmlValue(configFile.Stream, node, attribute); } private static string GetXmlValue(Stream stream, string node, string attribute) { var configDoc = XDocument.Load(stream); XElement temp = null; foreach (var n in node.Split('.')) { if (temp == null) { temp = configDoc.Element(n); continue; } temp = temp.Element(n); } if (temp == null) { throw new NullReferenceException(); } return temp.Attribute(attribute).Value; } } }
// ************************************************* // // 作者:bomo // 小组:WP开发组 // 创建日期:2014/6/21 14:55:56 // 版本号:V1.00 // 说明: // // ************************************************* // // 修改历史: // Date WhoChanges Made // 2014/6/21 14:55:56 bomo Initial creation // // ************************************************* using System.IO; using System.IO.IsolatedStorage; using XTuOne.Common.Helpers; namespace XTuOne.Utility.Helpers { /// <summary> /// 自定义应用程序配置(相当于IsolatedStorageSetting) /// </summary> public class ApplicationSetting { /// <summary> /// 保存配置的文件名 /// </summary> private readonly string filePath; private readonly SerializableDictionary<string, object> dictionary; public ApplicationSetting(string filePath) { this.filePath = filePath; //读取配置 using (var sf = IsolatedStorageFile.GetUserStoreForApplication()) { var directory = Path.GetDirectoryName(filePath); if (directory != null) { if (sf.DirectoryExists(directory)) { sf.CreateDirectory(directory); } } dictionary = sf.FileExists(filePath) ? XmlHelper.Deserialize<SerializableDictionary<string, object>>(filePath) : new SerializableDictionary<string, object>(); } } /// <summary> /// 通过索引赋值需要显式保存 /// </summary> public object this[string key] { get { return Contains(key) ? dictionary[key] : null; } set { dictionary[key] = value.ToString(); } } public T Get<T>(string key) { return (T) dictionary[key]; } /// <summary> /// 通过键获取值,如果不存在,则返回传入的默认值 /// </summary> public T Get<T>(string key, T defaultValue) { return dictionary.ContainsKey(key) ? (T) dictionary[key] : defaultValue; } /// <summary> /// 设置值,自动保存 /// </summary> public void Set(string key, object value) { if (dictionary.ContainsKey(key)) { dictionary[key] = value; } else { dictionary.Add(key, value); } Save(); } /// <summary> /// 保存配置到文件 /// </summary> public void Save() { XmlHelper.Serialize(filePath, dictionary); } /// <summary> /// 判断是否包含键 /// </summary> public bool Contains(string key) { return dictionary.ContainsKey(key); } /// <summary> /// 析构时保存数据 /// </summary> ~ApplicationSetting() { Save(); } } }
使用自定义的配置管理器可以控制文件信息,不会出现上述与第三方类库的一些兼容性问题(当然,这种情况比较少)
注意:该配置文件只支持基础类型,不支持复杂类型