WCF學習(三):資料契約序列化

iDotNetSpace發表於2009-05-18

    WCF能夠託管CLR型別,客戶端能傳遞和處理CLR型別的資料(如:string和int),但是如果我們自己定義的型別(如:宣告的Customer類)。其實WCF的傳遞CLR自己型別時,是因為已經把它序列化成了xml資訊集,而我們自己定義的型別則需要自己去顯示的宣告序列化。

序列化
    .net的序列化。.net是通過反射機制(反射機制參考文件)自動實現物件的序列化與反序列化。首先.net能夠捕獲物件每個欄位的值,然後進行序列化,反序列化時,.net建立一個對應型別的新的物件,讀取持久化的值,然後設定欄位的值。.net物件狀態的序列化到Stream中。
    我們自定義的類或者結構是不支援序列化的,因此如果我們的類是否要序列化是需要類的開發者來指定的。如果需要支援序列化的話,我們可以在類或者結構上新增Serializable屬性。
    如:
    [Serializable]
    public class Customer
    {
        ...
    }
    但是如果新增了Serializable就要求型別的成員也要支援序列化的,不然會丟擲異常,但是我們可以通過在成員上新增NonSerizlized屬性來說明這個成員不需要序列化。

格式器
    .net為序列化和反序列化提供了兩種格式器:
            1.BinaruFormatter:將型別序列化為二進位制格式。
            2.SoapFormatter:格式成SOAP特定的XML格式。
    但是這兩者都要將型別的程式集以及版本控制資訊持久化到Stream中,而面向服務要求參與者都能擁有型別程式集,所以如果用這兩種格式就必須要去共享Stream,這樣肯定不是我們理想的。從而有了WCF格式器。
   
    WCF的格式器:DataContractSerializer,是能夠共享資料契約的。WCF資料進行序列化時,WCF一般會自己呼叫DataContractSerializer來序列的,不需要我們去指定的。同時我們也可以用DataContractSerializer進行Stream的序列化。

資料契約特性
    Serializable要求型別的所有的成員都是可以序列化的,而且不支援型別名跟成員名的別名,這樣我們就沒法明確指定哪些成員是要放到資料契約中的。然而WCF資料契約特性DataContract很好的解決了這些問題。
    DataContract Attribute 是在名稱空間System.Runtime.Serialization中的,是可以在Enum、Struct、Class上標識的。擁有成員Name,Namespace。而當我們在一個class或者struct上使用時,wcf是不會序列化型別的成員的。如:
        [DataContract]
        public class Emloyee
        {
            public string _firstName;
            public string _lastName;
        }
Employee裡面的成員_firstName,_lastName是不會去序列化的,所以我們還必須去顯示的指定需要序列化的成員。
    DataMember Attribute是用來指定需要序列化型別的成員。DataMember的成員:
        IsRequried:序列化時是否必須要賦值;
        Name:指定成員的別名;
        Order:指定序列化後的排列位置。
我們看一個例子Customer.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;

namespace HenllyeeDataContract
{
    [DataContract(Name="Customer",Namespace="HenllyeeDataContract")]
    public class Customer
    {
        Fileds#region Fileds

        private string _firstName;
        private string _lastName;
        private int _age;
        private decimal _salary;

        #endregion
       
        Attributes#region Attributes
      
        [DataMember(Name="FirstName",IsRequired=false,Order=0)]
        public string FirstName
        {
            get { return this._firstName; }
            set { this._firstName = value; }
        }

        [DataMember(Name = "LastName", IsRequired = false, rder = 1)]
        public string LastName
        {
            get { return this._lastName; }
            set { this._lastName = value; }
        }

        [DataMember(Name = "Age", IsRequired = false, rder = 2)]
        public int Age
        {
            get { return this._age; }
            set { this._age = value; }
        }

        [DataMember(Name = "Salary", IsRequired = false, rder = 3)]
        public decimal Salary
        {
            get { return this._salary; }
            set { this._salary = value; }
        }

        #endregion
    }
}

 上面我們定義了一個資料契約,將DataMember屬性定義在幾個屬性上(建議定義在屬性上,不要定義在欄位上)。

服務契約為:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace HenllyeeServiceContract
{
    [ServiceContract(Name="CustomerManagerService",Namespace="http://Henllyee.cnblogs.com/2008/06/29")]
    public interface ICustomerManager
    {
        /**////


        /// Save customer's info
        ///

        /// the customer's object
        [OperationContract(Name="SaveCustomerInfo",Action="http://Henllyee.cnblogs.com/2008/06/29/CustomerManagerService/SaveCustomer",
            ReplyAction = "http://Henllyee.cnblogs.com/2008/06/29/CustomerManagerService/SaveCustomerResponse")]
        void SaveCustomer(HenllyeeDataContract.Customer customer);

        /**////


        /// Get customer's info
        ///

        /// a customer
        [OperationContract(Name = "GetCustomerInfo", Action = "http://Henllyee.cnblogs.com/2008/06/29/CustomerManagerService/GetCustomer",
            ReplyAction = "http://Henllyee.cnblogs.com/2008/06/29/CustomerManagerService/GetCustomerResponse")]
        HenllyeeDataContract.Customer GetCustomer();
    }
}

服務契約裡面具體實現:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace HenllyeeServiceContract
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class CustomerManager:ICustomerManager
    {
        fileds#region fileds

        private HenllyeeDataContract.Customer _customer;

        #endregion

        Members#region Members
       
        public void SaveCustomer(HenllyeeDataContract.Customer customer)
        {
            _customer = customer;
           
        }

        public HenllyeeDataContract.Customer GetCustomer()
        {
            return this._customer;
        }
        #endregion
    }
}

 

主機的實現就不在次給出了。
然後我們在客戶端新增服務引用,即可以了。我們在客戶端可以看到匯入的資料契約:

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
    [System.Runtime.Serialization.DataContractAttribute(Name="Customer", Namespace="HenllyeeDataContract")]
    [System.SerializableAttribute()]
    public partial class Customer : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
       
        [System.NonSerializedAttribute()]
        private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
       
        [System.Runtime.Serialization.OptionalFieldAttribute()]
        private string FirstNameField;
       
        [System.Runtime.Serialization.OptionalFieldAttribute()]
        private string LastNameField;
       
        [System.Runtime.Serialization.OptionalFieldAttribute()]
        private int AgeField;
       
        [System.Runtime.Serialization.OptionalFieldAttribute()]
        private decimal SalaryField;
       
        [global::System.ComponentModel.BrowsableAttribute(false)]
        public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
            get {
                return this.extensionDataField;
            }
            set {
                this.extensionDataField = value;
            }
        }
       
        [System.Runtime.Serialization.DataMemberAttribute()]
        public string FirstName {
            get {
                return this.FirstNameField;
            }
            set {
                if ((object.ReferenceEquals(this.FirstNameField, value) != true)) {
                    this.FirstNameField = value;
                    this.RaisePropertyChanged("FirstName");
                }
            }
        }
       
        [System.Runtime.Serialization.DataMemberAttribute()]
        public string LastName {
            get {
                return this.LastNameField;
            }
            set {
                if ((object.ReferenceEquals(this.LastNameField, value) != true)) {
                    this.LastNameField = value;
                    this.RaisePropertyChanged("LastName");
                }
            }
        }
       
        [System.Runtime.Serialization.DataMemberAttribute(Order=2)]
        public int Age {
            get {
                return this.AgeField;
            }
            set {
                if ((this.AgeField.Equals(value) != true)) {
                    this.AgeField = value;
                    this.RaisePropertyChanged("Age");
                }
            }
        }
       
        [System.Runtime.Serialization.DataMemberAttribute(Order=3)]
        public decimal Salary {
            get {
                return this.SalaryField;
            }
            set {
                if ((this.SalaryField.Equals(value) != true)) {
                    this.SalaryField = value;
                    this.RaisePropertyChanged("Salary");
                }
            }
        }
       
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
       
        protected void RaisePropertyChanged(string propertyName) {
            System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
            if ((propertyChanged != null)) {
                propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
            }
        }
    }

我們可以看到欄位後面都加上了Field字尾。
要注意的一點是:即使我們將DataMember定義在私有的欄位或者私有屬性上面,匯入的定義中,原來的私有欄位或私有屬性都會被重新定義成了公有欄位跟公有屬性。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-600249/,如需轉載,請註明出處,否則將追究法律責任。

相關文章