DataContractSerializer是WCF中优先选择的序列化方法。然而, 有时你需要使用默认序列化方法以外的方法。一个改变序列化方法的选项是使用XmlSerializer,包括实现自定义序列化的能力,共享类型和支持原有 网络服务的能力。对DataContractSerializer,XmlSerializer是WCF集成的一部分。这部分主要查看下 XmlSerializer并讨论它如何用来控制XML输出。
DataContractSerialzier总是使用XML元素进行序列化而不是使用XML属性。列表6.31显示了一个使用DataContractSerializer的Employee实例。
列表6.31 使用DataContractSerializer序列化Employee实例
1 | <?xml version= "1.0" encoding= "utf-16" ?> |
3 | <employeeID>12345</employeeID> |
4 | <firstName>Daniel</firstName> |
5 | <lastName>Dong</lastName> |
检查序列化XML,你可以数据契约可以使用XML属性被重写。一个使用XML属性而不是XML元素的例子在这里显示:
<Employee EmployeeID="101" FirstName="Daniel" LastName="Dong" />
XML属性不可能使用DataContractSerializer。DataContractSerializer通过允许XML元素的名字使用 [DataMember]属性确认来提供有限对XML的控制。NetDataContractSerializer本质与 DataContractSerializer是一样的但是支持共享类型信息。这意味着XmlSerializer是唯一的你可以对序列化输出完全控制的 序列化方法。列表6.32用XML属性显示了一段用于Employee类的元数据。
列表6.32 Employee XSD 元数据
01 | <?xml version= "1.0" encoding= "utf-8" ?> |
03 | <xs:complexType name= "Employee" > |
05 | <xs:attribute name= "EmployeeID" type= "xs:int" /> |
06 | <xs:attribute name= "FirstName" type= "xs:string" /> |
07 | <xs:attribute name= "LastName" type= "xs:string" /> |
10 | <xs:element name= "Employee" nillable= "true" type= "tns:Employee" /> |
使用属性的自定义XmlSerializer
你可以使用XmlSerializer在两种方式控制XML输出。第一种和最常用的方法是使用System.Xml.Serializer命名空间 下的.NET Framework来指导XmlSerializer如何控制XML输出。默认情况下,XmlSerializer将以XML元素输出公共字段和公共可读 /可写属性。这可以通过[XmlAttribute属性来改变XML属性。默认XmlSerializer将序列化公共字段和公共可读/可写属性除非使用 [XmlIgnore]告诉它不要进行序列化。额外的属性,比如[XmlElement],[XmlRoot],[XmlArray]和 [XmlArrayItem]属性,帮助指导XmlSerializer如何序列化类型。
使用IXmlSerializer自定义XmlSerialization
第二个使用XmlSerializer的方法是使用IXmlSerializable接口,一般用在高级场景中,需要对序列化进行完全控制。 IXmlSerializable接口支持三种方法: GetSchema,ReadXml和WriteXml. 在.NET 2.0 中,GetSchema方法被[XmlSchemaProvider]属性取代。另外两个方法是ReadXml和WriteXml.这些方法与用来反序列 化和序列化方法关联。列表6.33描述了这种情况。
列表6.33 使用XML序列化的Employee 类
002 | using System.Collections.Generic; |
005 | using System.Xml.Serialization; |
007 | using System.Xml.Schema; |
010 | namespace EmployeeSerialization |
012 | [XmlSchemaProvider( "MySchema" )] |
013 | public class Employee : IXmlSerializable |
017 | private int employeeID; |
018 | private string firstName; |
019 | private string lastName; |
025 | public Employee( int employeeID, string firstName, string lastName) |
027 | this .employeeID = employeeID; |
028 | this .firstName = firstName; |
029 | this .lastName = lastName; |
032 | public int EmployeeID |
034 | get { return employeeID; } |
035 | set { employeeID = value; } |
039 | public string FirstName |
041 | get { return firstName; } |
042 | set { firstName = value; } |
046 | public string LastName |
048 | get { return lastName; } |
049 | set { lastName = value; } |
052 | public static XmlQualifiedName MySchema(XmlSchemaSet schemaSet) |
054 | XmlSchema schema = XmlSchema.Read( new StringReader( |
055 | @"<xs:schema elementFormDefault=""qualified""" + |
056 | @" xmlns:tns="" + namespace + """ + |
057 | @" targetNamespace="" + namespace +""" + |
060 | @" <xs:element name=""Employee"">" + @"<xs:complexType>" + |
061 | @" <xs:attribute name=""EmployeeID"" type=""xs:int"" />" + |
062 | @" <xs:attribute name=""FirstName"" type=""xs:string"" />" + |
063 | @" <xs:attribute name=""LastName"" type=""xs:string"" />" + |
064 | @" </xs:complexType>" + |
066 | @" </xs:schema>" ), null ); |
067 | schemaSet.XmlResolver = new XmlUrlResolver(); |
068 | schemaSet.Add(schema); |
070 | return new XmlQualifiedName( "Employee" , ns); |
073 | public XmlSchema GetSchema() |
078 | public void ReadXml(XmlReader reader) |
081 | while (reader.IsStartElement()) |
083 | reader.MoveToContent(); |
086 | if (reader.IsStartElement( "Employee" )) |
088 | reader.MoveToContent(); |
090 | reader.MoveToContent(); |
092 | if (reader.IsStartElement( "ID" )) |
094 | reader.MoveToContent(); |
096 | this .employeeID = reader.ReadContentAsInt(); |
097 | reader.MoveToContent(); |
098 | reader.ReadEndElement(); |
100 | if (reader.IsStartElement( "FirstName" )) |
102 | reader.MoveToContent(); |
104 | this .firstName = reader.ReadContentAsString(); |
105 | reader.MoveToContent(); |
106 | reader.ReadEndElement(); |
108 | if (reader.IsStartElement( "LastName" )) |
110 | reader.MoveToContent(); |
112 | this .lastName = reader.ReadContentAsString(); |
113 | reader.MoveToContent(); |
114 | reader.ReadEndElement(); |
117 | reader.ReadEndElement(); |
120 | public void WriteXml(XmlWriter writer) |
122 | writer.WriteStartElement( "Employee" ); |
124 | writer.WriteStartElement( "ID" ); |
125 | writer.WriteValue( this .employeeID.ToString()); |
126 | writer.WriteEndElement(); |
128 | writer.WriteStartElement( "FirstName" ); |
129 | writer.WriteValue( this .firstName); |
130 | writer.WriteEndElement(); |
132 | writer.WriteStartElement( "LastName" ); |
133 | writer.WriteValue( this .lastName); |
134 | writer.WriteEndElement(); |
136 | writer.WriteEndElement(); |
使用XmlSerializer的结果是我们可以与XSD元数据一起工作并作为我们契约的开始点。不使用这个方法可能导致需要写很多代码。