WCF初探-24:WCF序列化和反序列化

前言

 

  • WCF包含不少封裝的內部機制,這些是咱們在編寫程序時不會常常看到的。好比上一篇講解的Message。這一篇我將講解WCF的另外一種內部機制,WCF的序列化和反序列化。一般咱們在編寫WCF服務程序的時候,咱們並無手動對WCF的數據傳遞作序列化和反序列化的操做,這是由於WCF默認經過序列化引擎DataContractSerializer幫咱們作了這些操做,使得開發人員只需關注數據對象定義自己(好比數據協定、消息協定),而沒必要關注數據對象的在WCF傳輸時的序列化機制。
  • DataContractSerializer 可在 .NET Framework 對象和 XML 之間進行雙向轉換。在對 .NET Framework 對象進行序列化時,序列化程序瞭解各類序列化編程模型,包括新的數據協定模型。此序列化程序支持下列類型:
  1. 基元類型(如:整數、字符串和字節數組)以及某些特殊類型(如 XmlElement 和 DateTime),這些特殊類型也被視爲基元類型。
  2. 數據協定類型(用 DataContractAttribute 屬性標記的類型)。
  3. 用 SerializableAttribute 屬性標記的類型,包括實現 ISerializable 接口的類型。
  4. 實現 IXmlSerializable 接口的類型。
  5. 許多常見集合類型,包括許多泛型集合類型。

 

使用DataContractSerializer序列化和反序列化

 

  • 對對象進行序列化最基本的方法是將其傳遞到 WriteObject 方法。該方法有三個重載,每一個重載分別用於寫入到 Stream、XmlWriter 或 XmlDictionaryWriter。使用 Stream 重載時,輸出是採用 UTF-8 編碼的 XML。使用 XmlDictionaryWriter 重載時,序列化程序會針對二進制 XML 優化其輸出。參考代碼以下:
   User user = new User { ID = 1, Name = "JACK", Age = 20, Nationality = "CHINA" };
    FileStream writer = new FileStream(fileName, FileMode.Create);
    DataContractSerializer ser =new DataContractSerializer(typeof(User));
    ser.WriteObject(writer, user);
    writer.Close();
  • 對對象進行反序列化的最基本的方式是調用 ReadObject 方法重載之一。該方法有三個重載,每一個重載分別用於讀取 XmlDictionaryReader、XmlReader 或 Stream。請注意,Stream 重載將建立不受任何配額保護的文本 XmlDictionaryReader,此重載僅應用於讀取受信任的數據。還請注意,必須將 ReadObject 方法返回的對象強制轉換爲適當的類型。參考代碼以下:
    FileStream fs = new FileStream(fileName,FileMode.Open);
    XmlDictionaryReader reader =XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
    DataContractSerializer ser = new DataContractSerializer(typeof(User));
    User deserializedUser =(User)ser.ReadObject(reader, true);

 

使用DataContractSerializer序列化和反序列化示例以下:

 

  • 建立一個名稱爲WcfDataContractSerializer的解決方案,添加一個名稱爲WcfDataContractSerializer的控制檯引用程序。修改Program.cs代碼以下:
using System;
using System.Runtime.Serialization;
using System.IO;
using System.Xml;

namespace WcfDataContractSerializer
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                WriteObject("DataContractSerializerExample.xml");
                ReadObject("DataContractSerializerExample.xml");

            }

            catch (SerializationException serExc)
            {
                Console.WriteLine("序列化失敗");
                Console.WriteLine(serExc.Message);
            }
            catch (Exception exc)
            {
                Console.WriteLine(
                "序列化操做失敗: {0} StackTrace: {1}",
                exc.Message, exc.StackTrace);
            }

            finally
            {
                Console.WriteLine("按 <Enter> 鍵退出....");
                Console.ReadLine();
            }
        }

        public static void WriteObject(string fileName)
        {
            Console.WriteLine("建立User對象並序列化它");
            User user = new User { ID = 1, Name = "JACK", Age = 20, Nationality = "CHINA" };
            FileStream writer = new FileStream(fileName, FileMode.Create);
            DataContractSerializer ser =new DataContractSerializer(typeof(User));
            ser.WriteObject(writer, user);
            writer.Close();
            Console.WriteLine("序列化User對象成功,請到程序Bin目錄下查看DataContractSerializerExample.xml文件");
        }

        public static void ReadObject(string fileName)
        {
            Console.WriteLine("反序列化實例對象");
            FileStream fs = new FileStream(fileName,FileMode.Open);
            XmlDictionaryReader reader =XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
            DataContractSerializer ser = new DataContractSerializer(typeof(User));
            User deserializedUser =(User)ser.ReadObject(reader, true);
            reader.Close();
            fs.Close();
            Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}", "ID", "Name", "Age", "Nationality");
            Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}",
                  deserializedUser.ID.ToString(),
                  deserializedUser.Name.ToString(),
                  deserializedUser.Age.ToString(),
                  deserializedUser.Nationality.ToString());
        }
    }

    [DataContract]
    public class User
    {
        [DataMember]
        public int ID { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Age { get; set; }
        [DataMember]
        public string Nationality { get; set; }
    }
}

 

  • 運行程序結果以下:

  

  打開程序Bin目錄下的DataContractSerializerExample.xml,顯示結果以下:編程

  

 

使用DataContractJsonSerializer序列化和反序列化

 

  • 使用DataContractJsonSerializer能夠將對象轉化爲Json格式,若是你習慣使用Json,那麼可使用該序列化引擎做爲對象的傳輸時的序列化工具。該序列化引擎和DataContractSerializer同樣,具備WriteObject和ReadObject方法,具體用法參照示例。
  • 注意:該序列化引擎只會對WCF的消息正文進行Json序列化操做,也就是說總個消息仍是基於SOAP的XML格式,只有Body部分變成了JSON字符串。

 

使用DataContractJsonSerializer序列化和反序列化示例

 

  • 在先前的解決方案上添加名稱爲WcfDataContractJsonSerializer的控制檯應用程序,修改Program.cs的代碼以下:
using System;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;

namespace WcfDataContractJsonSerializer
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("建立User對象並序列化它");
                User user = new User { ID = 1, Name = "JACK", Age = 20, Nationality = "CHINA" };
                string jsonString = Serialize<User>(user);
                Console.WriteLine(jsonString);

                Console.WriteLine("反序列化實例對象");
                User deserializedUser = Deserialize<User>(jsonString);
                Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}", "ID", "Name", "Age", "Nationality");
                Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}",
                      deserializedUser.ID.ToString(),
                      deserializedUser.Name.ToString(),
                      deserializedUser.Age.ToString(),
                      deserializedUser.Nationality.ToString());
            }

            catch (SerializationException serExc)
            {
                Console.WriteLine("序列化失敗");
                Console.WriteLine(serExc.Message);
            }
            catch (Exception exc)
            {
                Console.WriteLine(
                "序列化操做失敗: {0} StackTrace: {1}",
                exc.Message, exc.StackTrace);
            }

            finally
            {
                Console.WriteLine("按 <Enter> 鍵退出....");
                Console.ReadLine();
            }
        }

        public static string Serialize<T>(T item)
        {
            if (item == null) return string.Empty;
            var serializer = new DataContractJsonSerializer(item.GetType());
            using (var ms = new MemoryStream())
            {
                serializer.WriteObject(ms, item);
                var sb = new StringBuilder();
                sb.Append(Encoding.UTF8.GetString(ms.ToArray()));
                return sb.ToString();
            }
        }

        public static T Deserialize<T>(string jsonString)
        {
            if (string.IsNullOrEmpty(jsonString)) return default(T);
            var ser = new DataContractJsonSerializer(typeof(T));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)))
            {
                T jsonObject = (T)ser.ReadObject(ms);
                return jsonObject;
            }
        }
    }

    [DataContract]
    public class User
    {
        [DataMember]
        public int ID { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Age { get; set; }
        [DataMember]
        public string Nationality { get; set; }
    }
}

 

  • 運行結果以下:

  

 

序列化格式大小對比

 

  • 序列化格式的三種類型:XML文本類型、Json文本類型、二進制類型。接下來,咱們經過一個小示例來看看這三種類型序列化時的字節大小。由於咱們知道在網絡數據傳輸時,字節大小的傳遞顯得尤其重要呢。
  • 在先前的解決方案中添加名稱爲WcfSerializerCompare的控制檯應用程序,修改Program.cs的代碼以下:
using System;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Xml;

namespace WcfSerializerCompare
{
    class Program
    {
        static void Main(string[] args)
        {
            MemoryStream stream1 = new MemoryStream();
            MemoryStream stream2 = new MemoryStream();
            MemoryStream stream3 = new MemoryStream();
            User user = new User { ID = 1, Name = "JACK", Age = 20, Nationality = "CHINA" };

            DataContractSerializer xmlSerializer = new DataContractSerializer(typeof(User));
            xmlSerializer.WriteObject(stream1, user);

            DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(User));
            jsonSerializer.WriteObject(stream2, user);

            DataContractSerializer binarySerializer = new DataContractSerializer(typeof(User));
            XmlDictionaryWriter write = XmlDictionaryWriter.CreateBinaryWriter(stream3);
            binarySerializer.WriteObject(write, user);
            write.Flush();
     
            Console.WriteLine("XML文本字節數大小爲:{0}bytes", stream1.Length);
            Console.WriteLine("JSON文本字節數大小爲:{0}bytes", stream2.Length);
            Console.WriteLine("二進制字節數大小爲:{0}bytes", stream3.Length);

            Console.Read();

        }
    }

    [DataContract]
    public class User
    {
        [DataMember]
        public int ID { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Age { get; set; }
        [DataMember]
        public string Nationality { get; set; }
    }
}

 

  • 運行結果以下:

  

  從上面的示例能夠看出,採用Json文本傳輸的格式爲最小,只有53個字節數。json

相關文章
相關標籤/搜索