在现代Web开发中,数据的序列化与反序列化是常见的需求。Silverlight作为一种富互联网应用程序框架,虽然提供了基于XML的序列化机制,如DataContractSerializer和XmlSerializer,但这些机制并不支持纯二进制对象序列化。为了实现更高效的数据存储和传输,可以考虑使用Protobuf-net,这是一个基于Google Protobuf的C#实现,它提供了更紧凑且快速的二进制序列化方式。
Protobuf-net不仅支持纯.NET对象类的二进制序列化,还特别提供了Silverlight版本,使得可以将数据保存到本地磁盘,或者通过HTTP、TCP/IP套接字等方式加载到远程WCF服务器。Protobuf-net生成的是原始级别的byte[],这对于处理基本数据类型非常有用,尽管Silverlight的序列化器基于XML数据。
Protobuf-csharp-port是另一个优秀的C#版本的Protobuf实现,它遵循Java实现的大多数标准API和编码模式。它使用工具生成的编解码器为每个业务类服务。然而,选择了Protobuf-net作为Protobuf的基础二进制编解码引擎,因为它遵循了基本的.NET架构。它使用属性反射,但其性能足够快。此外,该引擎使能够更容易地使用干净的纯业务对象类和基本流类。在Silverlight中使用Protobuf-net程序集很容易,而使用Protobuf-csharp-port则需要进行一些代码修复工作。
在Silverlight中,可以使用IsolatedStorage将数据存储到本地硬盘。存储空间和位置是有限的,但在Silverlight Out-Of-Browser环境中可以解除这些限制。将使用IsolatedStorage与Protobuf-Net二进制序列化一起保存和加载数据。
将使用VS2008 SP1和Silverlight 3。应该添加Silverlight应用程序项目模板,并选择网站测试选项。项目最终布局的图像可以在本文的源代码中查看。可以在任何“Silverlight类库或应用程序”项目类型中使用protobuf-net程序集。这个SLBufferSerializer是一个Silverlight应用程序项目,它由VS2008自动生成Silverlight ASP.NET网站。
确保在网站上设置起始页面以使用F5。查看如何设置网站项目属性的图像。
让创建一个带有ProtoBuf-net的‘ProtoContract’和‘ProtoMember’属性的Person纯类。这种方法与XMLSerializer方法非常相似。下面属性的数字是Google的protobuf所要求的顺序。
C#
using System;
using ProtoBuf;
namespace SLBufferSerializer
{
[ProtoContract]
public class Person
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public Address Address { get; set; }
}
[ProtoContract]
public class Address
{
[ProtoMember(1)]
public string Line1 { get; set; }
[ProtoMember(2)]
public string Line2 { get; set; }
}
}
这是在Visual Studio中设计主显示XAML页面后的预览设计。可以在本文的源代码中查看详细的XAML代码。
这些是Protobuf-net序列化到IsolatedStorage的辅助方法。编解码引擎基本上使用流实现,因此IsolatedStorageStream类也是可用的。也可以将这些方法放置在另一个静态帮助类中:
C#
private static void SaveToStorage(string filePath, T instance)
{
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filePath, FileMode.CreateNew, storage))
{
Serializer.Serialize(stream, instance);
}
}
}
private static T LoadFromStorage(string filePath)
{
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, storage))
{
return Serializer.Deserialize(stream);
}
}
}
初始化一个person实例。让保存和加载person实例的序列化数据。
C#
...
using ProtoBuf;
namespace SLBufferSerializer
{
public partial class MainPage : UserControl
{
private readonly string fileName = "test.txt";
public MainPage()
{
InitializeComponent();
this.ProtobufSerialize();
}
private void ProtobufSerialize()
{
var person = new Person
{
Id = 12345,
Name = "Fred",
Address = new Address
{
Line1 = "Flat 1",
Line2 = "The Meadows"
}
};
try
{
SaveToStorage(fileName, person);
}
catch (IsolatedStorageException)
{
}
}
private void btnTest_Click(object sender, RoutedEventArgs e)
{
try
{
Person person = LoadFromStorage(fileName);
this.txtStatus.Text = "De-Serialized....";
this.txt1.Text = person.Id.ToString();
this.txt2.Text = person.Name;
this.txt3.Text = person.Address.Line1;
this.txt4.Text = person.Address.Line2;
}
catch (IsolatedStorageException)
{
}
}
...
}
}