對數據庫的備份必須序列化,重溫WCF之數據契約和序列化(四)

 2023-10-21 阅读 21 评论 0

摘要:一、數據契約 1.使用數據協定可以靈活控制哪些成員應該被客戶端識別。 [DataContract]public class Employee{[DataMember]public string Name { get; set; }[DataMember]public int Age { get; set; }[DataMember]public string City { get; set; }}[ServiceContract]public

一、數據契約

1.使用數據協定可以靈活控制哪些成員應該被客戶端識別。

    [DataContract]public class Employee{[DataMember]public string Name { get; set; }[DataMember]public int Age { get; set; }[DataMember]public string City { get; set; }}[ServiceContract]public interface IService{[OperationContract]Employee GetAEmployee();}public class MyService : IService{public Employee GetAEmployee(){return new Employee { Name = "小朋友", Age = 32 };}}class Program{static void Main(string[] args){using (ServiceHost host = new ServiceHost(typeof(Service1))){host.AddServiceEndpoint(typeof(IService1), new WSHttpBinding(), "http://127.0.0.1:8888/service1");ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();behavior.HttpGetEnabled = true;behavior.HttpGetUrl = new Uri("http://127.0.0.1:8888/service");  //httpGetUrl客戶端引用的地址
                host.Description.Behaviors.Add(behavior);host.Opened += delegate{Console.WriteLine("服務已啟動");Console.ReadKey();};host.Open();}}}

如果把Employee類中的某個成員的DataMember屬性去掉,則在客戶端代理類中就不會生成該屬性

2.數據協定也有隱藏真實身份的作用

    [DataContract(Name = "Worker")]public class Employee{[DataMember(Name = "Worker_Name")]public string Name { get; set; }[DataMember(Name = "Worker_Age")]public int Age { get; set; }[DataMember(Name = "Worker_City")]public string City { get; set; }}

對數據庫的備份必須序列化?這樣在客戶端生成的代理類的成員名稱就和服務器端不一樣

3.(已知類型),在一些比較復雜的類型無法反序列化(不能識別類型)的時候,就得考慮使用KnownTypeAttribute來標注可能涉及到的外部類型,但如果遇到像泛型這些較為復雜的類型,就要考慮在帶數據協定的類中添加一個靜態方法,該方法返回Type?的IEnumerable,一般是Type[]就可以了,而在KnownTypeAttribute的構造函數中使用這個方法的名字

[DataContract][KnownType("GetKnowTypes")]public class Student{[DataMember]public string Name;[DataMember]public string Phone;[DataMember]public AddrInfo Address;[DataMember]public object Scores;static Type[] GetKnowTypes(){return new Type[] { typeof(Dictionary<string,float>) };}}[DataContract]public class AddrInfo{[DataMember]public string Province;[DataMember]public string City;[DataMember]public string DetailAddr;}public class MyService : IService{public Student GetStudentInfo(){Student stu = new Student();AddrInfo info = new AddrInfo();info.Province = "廣東省";info.City = "佛山市";info.DetailAddr = "火星路-300號";stu.Name = "小陳";stu.Phone = "1388888888";stu.Address = info;Dictionary<string, float> m_scores = new Dictionary<string, float>();m_scores.Add("語文", 97f);m_scores.Add("英語", 64.5f);m_scores.Add("數學", 38f);m_scores.Add("歷史", 77.6f);m_scores.Add("地理", 82.3f);stu.Scores = m_scores;return stu;}}static void Main(string[] args){using (ServiceHost host = new ServiceHost(typeof(Service1))){host.AddServiceEndpoint(typeof(IService1), new WSHttpBinding(), "http://127.0.0.1:8888/service1");ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();behavior.HttpGetEnabled = true;behavior.HttpGetUrl = new Uri("http://127.0.0.1:8888/service");  //httpGetUrl客戶端引用的地址
                host.Description.Behaviors.Add(behavior);host.Opened += delegate{Console.WriteLine("服務已啟動");Console.ReadKey();};host.Open();}}static void Main(string[] args){WS.ServiceClient cli = new WS.ServiceClient();WS.Student stu = cli.GetStudentInfo();string msg = "學生姓名:{0}\n聯系電話:{1}\n" +"地址信息:-----------\n" +"省份:{2}\n" +"市區:{3}\n" +"詳細地址:{4}";Console.WriteLine(msg, stu.Name, stu.Phone, stu.Address.Province, stu.Address.City, stu.Address.DetailAddr);Console.WriteLine("---------------------------------------");Console.WriteLine("學生成績單:");Dictionary<string, float> scores = stu.Scores as Dictionary<string, float>;foreach (var item in scores){Console.Write("{0}:{1}\n", item.Key, item.Value);}Console.ReadKey();}

使用[ServiceKnownType(typeof(Order))]放在服務契約上,使用[KnownType(typeof(Order))]放在數據契約上

[ServiceContract][ServiceKnownType(typeof(Order))]//可以放到這里public interface IService1{[OperationContract]//[ServiceKnownType(typeof(Order))]也可以放到這里void AddOrder(OrderBase order);}[DataContract]// [KnownType(typeof(Order))]也可以放到這里public abstract class OrderBase{[DataMember]public Guid ID { get; set; }[DataMember]public DateTime Date { get; set; }[DataMember]public string Customer { get; set; }[DataMember]public string ShipAddress { get; set; }}[DataContract]public class Order : OrderBase{[DataMember]public double TotalPrice { get; set; }}public class Service1 : IService1{public void AddOrder(OrderBase order){Console.WriteLine(order.Customer);}}public class Program{static void Main(string[] args){using (Service1Client client = new Service1Client()){Order order = new Order() { Customer = "yxl" };client.AddOrder(order);}Console.ReadKey();}}

如果不標識ServiceKnownType或KnownType,客戶端將不會生成Order類

二、序列化

wcf文斯莫克。1.NET序列化機制

?  在.NET Framework 3.0之前,提供了3中序列化器,序列化器理解為把可序列化的類型序列化成XML的類。這三種序列化器分別是BinaryFormatter、SoapFormatter和XmlSerializer類。下面分別介紹下這3種序列化器。

  • BinaryFormatter類:把.NET Object序列化成二進制格式。在這個過程,對象的公共字段和私有字段以及類名稱(包括類的程序集名),將轉換成成字節流。
  • SoapFormatter類:把.NET Object序列化成SOAP格式,SOAP是一種輕量、簡單的,基于XML的協議。只序列化字段,包括公共字段和私有字段
  • XmlSerializer類:該類僅僅序列化公共字段和屬性,且不保存類型的保真度。

  對于這三種序列化機制,BinaryFormatter二進制序列化的優點是:性能高,但是不能跨平臺。而SoapFormatter,XmlSerializer的優點是:跨平臺、互操作性好,并且可讀性強,但是傳輸性能不及BinaryFormatter。

原有的格式化器需要將類型的程序集及版本控制信息持久化到流中,以保證對象被反序列化為正確的類型,這種方式一定程度上妨礙面向服務交互。原因如下:BinaryFormatter和SoapFormatter具備類型保真,它們要求其所在程序集、版本等信息必須完全一致,如果不同則視為是不同類型的對象,這就要求客戶端必須擁有原有的.NET 程序集。面向服務的交互方式應該更傾向于平臺無關,并最大限度的解耦,因此這2個格式化器顯然與WCF有些不搭。再看XmlSerializer格式化器,在功能上與DataContractSerializer格式器類似,但是為何沒有使用XmlSerializer格式器而是引人新格式器,我的理解如下:在SOA服務的構建過程中,提倡契約優先的構建原則,也就是說我們應該優先構建契約后構建具體的代碼,在構建過程中并不考慮其具體的序列化過程。(契約優先相對于代碼優先在設計層面具有更高的抽象程度,降低了服務設計與平臺的耦合度,因此我更傾向于契約優先的開發順序。)此外,XmlSerializer為如何將數據表示成XML提供了精確的控制,DataContractSerializer則提供了較少的控制,所以DataContractSerializer的序列化過程是可預知的,容易優化,所以它與XmlSerializer相比有更好的性能(我查到的數字是提升了約10%)。  

2.WCF中序列化機制

序列化數據的安全性。在WCF中,提供了專門用來序列化和反序列操作的類,該類就是DataContractSerializer類。一般而言,WCF會自動選擇使用DataContractSerializer來對可序列話數據契約進行序列化,不需要開發者直接調用。WCF除了支持DataContractSerializer類來進行序列化外,還支持另外兩種序列化器,這兩種序列化器分別為:XMLSerializer(定義在System.XML.Serialization namespace)和NetDataContractSerializer?(定義在System.XML.Serialization namespace)。XmlSerializer類不是WCF專用的類,Asp.net Web服務統一使用該類作為序列化器,但XmlSerializer類支持的類少于DataContractSerializer列支持的類型,但它允許對生成的XML進行更多的控制,并且支持更多的XML架構定義語言(XSD)標準。它不需要在可序列化類上有任何聲明性的屬性。

  默認情況下,WCF 使用?DataContractSerializer?類來序列化數據類型。?此序列化程序支持下列類型:

  • 基元類型(如:整數、字符串和字節數組)以及某些特殊類型(如?XmlElement?和?DateTime)。
  • 數據協定類型(用?DataContractAttribute?屬性標記的類型)。
  • 用?SerializableAttribute?屬性標記的類型,包括實現?ISerializable?接口的類型。
  • 實現?IXmlSerializable?接口的類型。
  • 許多常見集合類型,包括許多泛型集合類型。

  DataContractSerializer類與NetDataContractSerializer類類似,它們之間主要的區別在于:在使用NetDataContractSerializer進行序列化時,不需要指定序列化的類型,如:

NetDataContractSerializer serializer =new NetDataContractSerializer();  // 不需要明確指定序列化的類型
serializer.WriteObject(writer, p);// 而使用DataContractSerializer需要明確指定序列化的類型
DataContractSerializer serializer =new DataContractSerializer(typeof(Order)); // 需要明確指定序列化的類型serializer.WriteObject(writer, p);

SerializableAttribute與DataContract異同。

相同點:都是標記類型為可序列化類型

wcf框架、不同點:在于序列化的成員不一樣,DataContract是Opt-in(明確參與)的方式,即使用DataMember特性明確標識哪些成員需要序列化,而Serializable是Opt-out方式,即使用NoSerializable特性明確標識不參與序列化的成員。

我個人意見,DataContractSerializable就用在它應該用的地方吧,如果不是用WCF,還是不要用它了,它的序列化結果有一些微軟專屬的東西。對于來自網絡的松散Xml接口數據,XmlSerializer是不二之選。如果想把對象完整地保存下來(數據與狀態),同時又不需要被人看。那就用BinaryFormatter吧,SerializableAttribute默認是使用BinaryFormatter序列化的。

轉載于:https://www.cnblogs.com/yxlblogs/p/3765681.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/155730.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息