XML 序列化僅將對象的公共字段和屬性值序列化為 XML 流。XML 序列化不包括類型信息。例如,如果您有一個存在於 Library 命名空間中的 Book 對象,將不能保證它將會被反序列化為同一類型的對象。
注意 XML 序列化不轉換方法、索引器、私有字段或只讀屬性(只讀集合除外)。若要序列化對象的所有字段和屬性(公共的和私有的),請使用 BinaryFormatter,而不要使用 XML 序列化。
XML 序列化中最主要的類是 XmlSerializer 類,它的最重要的方法是 Serialize 和 Deserialize 方法。XmlSerializer 生成的 XML 流符合萬維網聯合會 (www.w3.org) XML 架構定義語言 (XSD) 1.0 的建議。另外,生成的數據類型符合標題為“XML Schema Part 2: Datatypes”(XML 架構第二部分:數據類型)的文檔。
對象中的數據是用編程語言構造(如類、字段、屬性、基元類型、數組,甚至 XmlElement 或 XmlAttribute 對象形式的嵌入 XML)來描述的。您可以創建自己的用屬性批注的類,或者使用 XML 架構定義工具生成基於現有 XML 架構的類。
如果您有 XML 架構,就可運行 XML 架構定義工具生成一組強類型化為架構並用屬性批注的類。當序列化這樣的類的實例時,生成的 XML 符合 XML 架構。使用這樣的類,就可針對容易操作的對象模型進行編程,同時確保生成的 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”的萬維網聯合會文檔的第 5 節。有關此過程的更多信息,請參見用 XML 序列化生成 SOAP 消息。有關控制生成的 XML 的屬性表,請參見控制編碼的 SOAP 序列化的屬性。
XmlSerializer 類生成由 XML Web services 創建和傳遞給 XML Web services 的 SOAP 消息。若要控制 SOAP 消息,可將屬性應用於 XML Web services 文件 (.asmx) 中的類、返回值、參數和字段。您可以同時使用在“控制 XML 序列化的屬性”中列出的屬性和在“控制編碼的 SOAP 序列化的屬性”中列出的屬性,因為 XML Web services 可以使用文本樣式,也可以使用編碼的 SOAP 樣式。有關使用屬性控制 XML Web services 所生成的 XML 的更多信息,請參見 XML Web services 的 XML 序列化。有關 SOAP 和 XML Web services 的更多信息,請參見自定義 SOAP 消息。
保護 XmlSerializer 應用程序
在創建使用 XmlSerializer 的應用程序時,您應當了解以下幾點以及它們的影響:
- XmlSerializer 創建 C# 文件 (.cs 文件),並將其編譯成 .dll 文件,這些 .dll 文件位於由 TEMP 環境變量指定的目錄中;這些 DLL 文件將發生序列化。
代碼和 DLL 在創建和進行編譯時,易於遭受惡意進程的攻擊。如果所使用的計算機運行的是 Microsoft Windows NT 4.0 或更高版本,則有可能會有兩個或更多用戶共享臨時目錄。如果同時存在以下兩種情況,則共享臨時目錄是有危險性的:(1) 兩個帳戶有不同的安全特權;(2) 具有較高特權的帳戶運行一個使用 XmlSerializer 的應用程序。在這種情況下,某一用戶可以替換所編譯的 .cs 或 .dll 文件,由此破壞計算機的安全性。為了避免發生這一問題,請始終確保計算機上的每一帳戶都有自己的配置文件。如果能夠保證這一點的話,默認情況下,TEMP 環境變量就會為不同的帳戶指定不同的目錄。
- 如果一名惡意用戶向 Web 服務器發送持續的 XML 數據流(拒絕服務攻擊),XmlSerializer 會一直處理這一數據,直到計算機資源不夠用才停止。
如果您所使用的計算機運行 Internet 信息服務 (IIS),並且您的應用程序是在 IIS 下運行,就可以避免這類攻擊。IIS 帶有一個控制門,用於禁止處理大於設定數量(默認值是 4 KB)的數據流。如果您所創建的應用程序不使用 IIS,同時該應用程序使用 XmlSerializer 進行反序列化,則應該實現一個類似的控制門,以阻止拒絕服務攻擊。
- XmlSerializer 將使用給予它的任何類型,對數據進行序列化,並運行任何代碼。
惡意對象施加威脅的方式有兩種。一種是運行惡意代碼,另一種是將惡意代碼插入到由 XmlSerializer 創建的 C# 文件中。在第一種情況下,如果惡意對象試圖運行破壞性過程,代碼訪問安全性將幫助防止發生任何破壞。在第二種情況下,在理論上,惡意對象有可能會以某種方式將代碼插入到由 XmlSerializer 創建的 C# 文件中。盡管對這一問題已進行了徹底的檢驗,而且這類攻擊被認為是不可能的,但您還是應該小心一些,一定不要序列化那些不可信的未知類型的數據。
- 已序列化的重要數據可能易於遭到攻擊。
XmlSerializer 對數據進行了序列化之后,數據可以被存儲為 XML 文件,或存儲在其他數據存儲區。如果其他進程可以訪問到您的數據存儲區,或是可以在 Intranet 或 Internet 上看到該數據存儲區,數據就可能被竊取,並被惡意使用。例如,如果您創建了一個應用程序,對包含信用卡號碼的訂單進行序列化,這一數據就非常重要。為了防止發生這一問題,請始終保護您的數據存儲區,並對數據采取保密措施。
簡單類的序列化
下面的示例顯示一個具有公共字段的簡單類:
[Visual Basic]Public Class OrderForm Public OrderDate As DateTimeEnd 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 類構造函數。
- 調用 Serialize 方法以生成對象的公共屬性和字段的 XML 流表示形式或文件表示形式。下面的示例創建一個文件。
[Visual Basic]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 方法以產生該對象的副本。在反序列化時,必須將返回的對象強制轉換為原始對象的類型,如下面的示例中所示。下面的示例將該對象反序列化為文件,盡管它也可以被反序列化為流。
[Visual Basic]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 序列化的好處
XmlSerializer 類在您將對象序列化為 XML 時為您提供完整而靈活的控制。如果您正在創建 XML Web services,則可以將控制序列化的屬性應用於類和成員以確保 XML 輸出符合特定的架構。
例如,XmlSerializer 使您能夠:
- 指定應將字段或屬性編碼為特性還是元素。
- 指定要使用的 XML 命名空間。
- 如果字段或屬性名不合適,則指定元素或特性的名稱。
XML 序列化的另一個好處是:只要生成的 XML 流符合給定的架構,則對於所開發的應用程序就沒有約束。假定有這樣一個用於描述圖書的架構,它具有標題、作者、出版商和 ISBN 編號元素。您可以開發一個以您希望的任何方式(例如,作為圖書訂單,或作為圖書清單)處理 XML 數據的應用程序。在任一種情況下,唯一的要求是 XML 流應當符合指定的 XML 架構定義語言 (XSD) 架構。
XML 序列化注意事項
使用 XmlSerializer 類時,應考慮下列情況:
- 序列化數據只包含數據本身以及類的結構。不包括類型標識和程序集信息。
- 只能序列化公共屬性和字段。如果需要序列化非公共數據,請使用 BinaryFormatter 類而不是 XML 序列化。
- 類必須有一個將由 XmlSerializer 序列化的默認構造函數。
- 不能序列化方法。
- XmlSerializer 可以以不同方式處理實現 IEnumerable 或 ICollection 的類(條件是這些類滿足某些要求)。實現 IEnumerable 的類必須實現帶單個參數的公共 Add 方法。Add 方法的參數必須與從 GetEnumerator 方法返回的 IEnumerator.Current 屬性所返回的類型一致(多態)。除實現 IEnumerable 外還實現 ICollection 的類(如CollectionBase)必須有一個取整數的公共 Item 索引屬性(在 C# 中為索引器),並且它必須有一個整數類型的公共 Count 屬性。傳遞給 Add 方法的參數必須與從 Item 屬性返回的類型相同或與該類型的某個基的類型相同。對於實現 ICollection 的類,要序列化的值將從索引 Item 屬性檢索,而不是通過調用 GetEnumerator 來檢索。另外請注意,除返回另一個集合類(實現 ICollection 的集合類)的公共字段之外,將不序列化公共字段和屬性。有關示例,請參見 XML 序列化的示例。
XSD 數據類型映射
標題為“XML Schema Part 2: Datatypes”的萬維網聯合會 (www.W3.org) 文檔指定在 XML 架構定義語言 (XSD) 架構中允許使用的簡單數據類型。對於這些數據類型中的許多類型(例如,int 和 decimal),在 .NET Framework 中都有對應的數據類型。但是,某些 XML 數據類型在 .NET Framework 中沒有對應的數據類型(例如,NMTOKEN數據類型)。在這樣的情況下,如果使用 XML 架構定義工具 (Xsd.exe) 從架構生成類,就會將適當的特性應用於字符串類型的成員,並會將其 DataType 屬性設置為 XML 數據類型名稱。例如,如果架構包含一個數據類型為 XML 數據類型 NMTOKEN 的、名為“MyToken”的元素,則生成的類可能包含以下示例中的成員。
[Visual Basic]<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。