XML 序列化簡介
序列化是將物件轉換為易於傳輸之格式的程序。例如,您可序列化物件並使用 HTTP 透過網際網路在用戶端和伺服器之間傳輸它。相反地,還原序列化則會從資料流重建物件。
XML 序列化只會將物件的公用欄位和屬性值序列化為 XML 資料流。XML 序列化並不包含型別資訊。例如,如果 Library 命名空間中有個 Book 物件,則並不保證會將它還原序列化為相同型別的物件。
**注意 **XML 序列化不會轉換方法、索引子 (Indexer)、私用 (Private) 欄位或唯讀屬性 (唯讀集合則除外)。若要序列化物件的所有欄位和屬性 (包括公用和私用的),請使用 BinaryFormatter,而不要使用 XML 序列化。
XML 序列化中的主要類別是 XmlSerializer 類別,而它最重要的方法是 Serialize 和 Deserialize 方法。由 XmlSerializer 產生的 XML 資料流符合全球資訊網協會 (www.w3.org) XML 結構描述定義語言 (XSD) 1.0 建議事項。除此之外,所產生的資料型別也符合標題為<XML Schema Part2: Datatypes>的文件。
您物件中的資料是使用程式語言建構描述的,這些建構包括類別、欄位、屬性、基本型別 (Primitive Type)、陣列和甚至以 XmlElement 或 XmlAttribute 物件為格式的內嵌 XML。您可選擇建立自己的類別,使用屬性加註,或是使用 XML 結構描述定義工具來以現有 XML 結構描述為基礎產生類別。
如果您具有 XML 結構描述,您可執行 XML 結構描述定義工具來產生強型別為結構描述的一組類別,並使用屬性來加註。當序列化這種類別的執行個體 (Instance) 時,產生的 XML 會與 XML 結構描述相符。您可使用這種類別來撰寫易於操作的物件模型 (Object Model),而同時又能確保產生的 XML 與 XML 結構描述相符。如此一來,您不需使用 .NET Framework 中的其他類別 (例如 XmlReader 和 XmlWriter 類別) 便可剖析和寫入 XML 資料流 (如需使用這些類別的詳細資訊,請參閱在 .NET Framework 內採用 XML)。這些類別允許您剖析任何 XML 資料流。相反地,當 XML 資料流必須與已知的 XML 結構描述相符時,請使用 XmlSerializer。
屬性控制由 XmlSerializer 類別產生的 XML 資料流,允許您設定 XML 資料流的 XML 命名空間、項目名稱、屬性名稱等等。如需這些屬性以及它們如何控制 XML 序列化的詳細資訊,請參閱使用屬性控制 XML 序列化。如需用來控制所產生 XML 之那些屬性的列表,請參閱控制 XML 序列化的屬性。
XmlSerializer 類別可進一步序列化物件並產生編碼的 SOAP XML 資料流。產生的 XML 符合標題為<Simple Object Access Protocol (SOAP) 1.1>的全球資訊網協會文件的第五節。如需這個處理序 (Process) 的詳細資訊,請參閱使用 XML 序列化產生 SOAP 訊息。如需控制所產生 XML 的屬性的列表,請參閱控制編碼 SOAP 序列化的屬性。
XmlSerializer 類別會產生由 XML Web Service 建立和傳遞至 XML Web Service 的 SOAP 訊息。若要控制 SOAP 訊息,您可將屬性套用至 XML Web Service 檔案 (.asmx) 中找到的類別、傳回值、參數和欄位。您可使用列於<控制 XML 序列化的屬性>和<控制編碼 SOAP 序列化的屬性>當中的屬性,因為 XML Web Service 可使用常值 (Literal) 或編碼 SOAP 樣式。如需使用屬性來控制 XML Web Service 產生的 XML 的詳細資訊,請參閱 XML Web Service 的 XML 序列化。如需 SOAP 和 XML Web Service 的詳細資訊,請參閱自訂 SOAP 訊息。
保護 XmlSerializer 應用程式
建立使用 XmlSerializer 的應用程式時,您應該留意下列事項和它們的含意:
XmlSerializer 可建立 C# 檔案 (.cs 檔案) 並將它們編譯成 TEMP 環境變數指名目錄中的 .dll 檔;序列化程序會隨著這些 DLL 產生時執行。
程式碼和 DLL 檔在建立及編譯 (Compilation) 過程中很容易遭到惡意處理序的破壞。使用執行 Microsoft Windows NT 4.0 (含) 以後版本的電腦時,可能會有兩個或兩個以上使用者共用暫存目錄。在下列狀況下使用共用暫存目錄會有危險:(1) 兩個帳戶擁有不同的安全使用權限,而且 (2) 使用權限較高的帳戶執行使用 XmlSerializer 的應用程式。在這種情況下,其中一個使用者有可能會置換已編譯的 .cs 或 .dll 檔而破壞系統的安全。為了消除這個疑慮,請務必確定電腦上的每一個帳戶都有自己的設定檔,如此,依預設,TEMP 環境變數就會針對每一個帳戶指向不同的目錄。
如果有惡意使用者傳送 XML 資料的連續資料流到 Web 伺服器 (即拒絕服務的攻擊),XmlSerializer 便會不斷地處理資料,直到電腦資源不足為止。
如果您使用執行 Internet Information Services (IIS) 的電腦,並在 IIS 內部執行您的應用程式,就可以阻擋這種攻擊。IIS 提供一道閘門,這道匣門不會處理超過固定長度 (預設值為 4 KB) 的資料流。如果您建立不使用 IIS 的應用程式,又以 XmlSerializer 將它還原序列化,則應該採用類似的閘門,以預防拒絕服務的攻?。
XmlSerializer 會將資料序列化並使用給定的型別來執行任何程式碼。
惡意物件產生威脅的方法有兩種。它可以執行惡意程式碼,或是將惡意程式碼插入 XmlSerializer 建立的 C# 檔案。在第一種情況中,如果惡意物件嘗試執行破壞程序,程式碼存取安全性將有助於防止任何破壞行為發生。在第二種情況中,理論上惡意程式碼有可能會以某種方式將程式碼插入 XmlSerializer 建立的 C# 檔案。雖然我們已經仔細審核這個問題,也認為發生這類攻擊的機會不可能發生,但您還是應該小心防範,不要使用不明又不可靠的型別來序列化資料。
已序列化的敏感資料可能很容易受到攻擊。
在 XmlSerializer 將資料序列化之後,就可以將它另存成 XML 檔案或其他資料存放區。如果您的資料存放區可供其他處理序使用,或是可以在 Intranet 或 Internet 上檢視,資料就有可能被竊取或遭惡意使用。例如,如果您建立一個應用程式來序列化內含信用卡號碼的訂購單,這些資料便非常敏感。為了利於預防這種狀況,請隨時保護資料的存放區並維持它的私用設定。
簡單類別的序列化
下列範例顯示具有一公用欄位的簡單類別:
Public Class OrderForm
Public OrderDate As DateTime
End Class
[C#]
public class OrderForm{
public DateTime OrderDate;
}
當序列化這個類別的執行個體時,它可能像這樣:
<OrderForm>
<OrderDate>12/12/01</OrderDate>
</OrderForm>
如需序列化的更多範例,請參閱 XML 序列化的範例。
可序列化的項目
您可使用 XmLSerializer 類別序列化下列項目。
- 公用類別的公用讀取/寫入屬性和欄位
- 實作 ICollection 或 IEnumerable 的類別。(請注意,只會序列化集合,公用屬性並不會序列化)。
- XmlElement 物件。
- XmlNode 物件。
- DataSet 物件。
序列化和還原序列化物件
若要序列化物件,首先建立要序列化的物件,並且設定它的公用屬性和欄位。若要這麼做,您必須決定要將 XML 資料流以哪種傳輸格式儲存,也就是要決定將其儲存為資料流還是檔案。例如,如果必須將 XML 資料流以永久格式儲存,請建立 FileStream 物件。當您還原序列化物件時,傳輸格式會決定您將建立的是資料流或檔案物件。一旦決定傳輸格式後,您可視需要呼叫 Serialize 或 Deserialize 方法。
若要序列化物件
建立物件並設定其公用欄位和屬性。
使用物件的型別建構 XmlSerializer。如需詳細資訊,請參閱 XmlSerializer 類別建構函式 (Constructor)。
呼叫 Serialize 方法來產生 XML 資料流或檔案,表示物件的公用屬性和欄位。下列範例將建立檔案。
Dim myObject As MySerializableClass = New MySerializableClass() ' Insert code to set properties and fields of the object. Dim mySerializer As XmlSerializer = New XmlSerializer(GetType(MySerializableClass)) ' To write to a file, create a StreamWriter object. Dim myWriter As StreamWriter = New StreamWriter("myFileName.xml") mySerializer.Serialize(myWriter, myObject) [C#] MySerializableClass myObject = new MySerializableClass(); // Insert code to set properties and fields of the object. XmlSerializer mySerializer = new XmlSerializer(typeof(MySerializableClass)); // To write to a file, create a StreamWriter object. StreamWriter myWriter = new StreamWriter("myFileName.xml"); mySerializer.Serialize(myWriter, myObject);
若要還原序列化物件
使用要還原序列化的物件型別建構 XmlSerializer。
呼叫 Deserialize 方法來產生物件的複本。當還原序列化時,您必須將傳回的物件轉型為原始物件的型別,如下列範例所示。下列範例會將物件還原序列化為檔案,不過也可將它還原序列化為資料流。
Dim myObject As MySerializableClass ' Constructs an instance of the XmlSerializer with the type ' of object that is being deserialized. Dim mySerializer As XmlSerializer = New XmlSerializer(GetType(MySerializableClass)) ' To read the file, creates a FileStream. Dim myFileStream As FileStream = _ New FileStream("myFileName.xml", FileMode.Open) ' Calls the Deserialize method and casts to the object type. myObject = CType( _ mySerializer.Deserialize(myFileStream), MySerializableClass) [C#] MySerializableClass myObject; // Constructs an instance of the XmlSerializer with the type // of object that is being deserialized. XmlSerializer mySerializer = new XmlSerializer(typeof(MySerializableClass)); // To read the file, creates a FileStream. FileStream myFileStream = new FileStream("myFileName.xml", FileMode.Open); // Calls the Deserialize method and casts to the object type. myObject = (MySerializableClass) mySerializer.Deserialize(myFileStream)
如需 XML 序列化的更多範例,請參閱 XML 序列化的範例。
使用 XML 序列化的好處
當您將物件序列化為 XML 時,XmlSerializer 類別能夠讓您完全並彈性地進行控制。如果您正在建立 XML Web Service,您可將控制序列化的屬性套用至類別和成員,確保 XML 輸出與特定結構描述相符。
例如,XmlSerializer 讓您能夠:
- 指定欄位或屬性 (Property) 是否應編碼為屬性 (Attribute) 或項目。
- 指定要使用的 XML 命名空間。
- 在欄位或屬性 (Property) 名稱不適當時指定項目或屬性 (Attribute) 的名稱。
使用 XML 序列化的另一個好處是,您對開發的應用程式並沒有任何條件約束 (Constraint),只要產生的 XML 資料流與指定結構描述相符即可。假設有個用來描述書籍的結構描述,其中有標題、作者、出版社和 ISBN 編號項目。您可開發依您要的任何方式處理 XML 資料的應用程式,例如開發為購書訂單或是書籍存貨。無論是哪種情況,唯一的要求是 XML 資料流必須與指定的 XML 結構描述定義語言 (XSD) 結構描述相符。
XML 序列化的考量
當使用 XmlSerializer 類別時,您應將下列事項列入考量:
- 序列化的資料只包含資料本身和您的類別的結構;不包含型別識別 (Identity) 和組件資訊。
- 只可以序列化公用屬性和欄位。如果您需要序列化非公用的資料,請使用 BinaryFormatter 類別,而不要使用 XML 序列化。
- 類別必須具有由 XmlSerializer 序列化的預設建構函式。
- 無法序列化方法。
- XmlSerializer 可處理以不同方式實作 IEnumerable 或 ICollection 的類別,不過要在符合特定的條件下才能這麼做。實作 IEnumerable 的類別必須實作使用單一參數的公用 Add 方法。Add 方法的參數必須與 IEnumerator.Current 屬性 (從 GetEnumerator 方法傳回) 傳回的型別一致 (多型)。除了實作 IEnumerable 之外還實作 ICollection (例如 CollectionBase) 的類別必須具有使用整數的公用 Item 索引屬性 (C# 中為索引子),而且還必須具有整數型別的公用 Count 屬性。傳遞至 Add 方法的參數必須與 Item 屬性傳回的型別或是與該型別的任一基底 (Base) 屬於相同的型別。針對實作 ICollection 的類別,要序列化的值會從索引 Item 屬性擷取,而不是藉由呼叫 GetEnumerator。另外也請注意,公用欄位和屬性不會進行序列化,但傳回其他集合類別 (即實作 ICollection 的類別) 的公用欄位則除外。如需範例,請參閱 XML 序列化的範例。
XSD 資料型別對應
在標題為<XML Schema Part2: Datatypes」的全球資訊網協會 (www.W3.org) 文件中,對可在 XML 結構描述定義語言 (XSD) 結構描述中使用的簡單資料型別加以指定。對於其中許多型別來說 (例如 int 和 decimal),.NET Framework 中都有對應的資料型別。不過,有些 XML 資料型別在 .NET Framework 中並沒有對應的資料型別 (例如 NMTOKEN 資料型別)。在這種情況下,如果您使用 XML 結構描述定義工具 (Xsd.exe) 來從結構描述產生類別,則適當屬性會套用至字串型別的成員,並且將其 DataType 屬性設定為 XML 資料型別名稱。例如,如果結構描述包含名為「MyToken」的項目,且它的 XML 資料型別為 NMTOKEN,則產生的類別可能會包含下列範例中顯示的成員。
<XmlElement(DataType:="NMTOKEN")>
Public MyToken As String
[C#]
[XmlElement(DataType = "NMTOKEN")]
public string MyToken;
同樣地,如果您正在建立必須與特定 XML 結構描述 (XSD) 相符的類別,您應套用適當屬性並將其 DataType 屬性設定為所需的 XML 資料型別名稱。
如需型別對應的完整清單,請參閱下列任一屬性類別的 DataType 屬性:SoapAttributeAttribute、SoapElementAttribute、XmlArrayItemAttribute、XmlAttributeAttribute、XmlElementAttribute 或 XmlRootAttribute。
請參閱
XML 和 SOAP 序列化 | XMLSerializer.Serialize | BinaryFormatter | 二進位序列化 | 序列化物件 | XmlSerializer | FileStream | XML 序列化的範例