Types that implement the IXmlSerializable interface are fully supported by the DataContractSerializer. TheXmlSchemaProviderAttribute attribute should always be applied to these types to control their schema.
Caution: |
---|
If you are serializing polymorphic types you must apply the XmlSchemaProviderAttribute to the type to ensure the correct type is serialized. |
There are three varieties of types that implement IXmlSerializable: types that represent arbitrary content, types that represent a single element, and legacy DataSet types.
When serializing a data member of a type that implements IXmlSerializable and is a content type as defined previously, the serializer writes the wrapper element for the data member and passes control to the WriteXml method. The WriteXmlimplementation can write any XML, which includes adding attributes to the wrapper element. After WriteXml is done, the serializer closes the element.
When deserializing a data member of a type that implements IXmlSerializable and is a content type as defined previously, the deserializer positions the XML reader on the wrapper element for the data member and passes control to the ReadXmlmethod. The method must read the entire element, including the start and end tags. Make sure your ReadXml code handles the case where the element is empty. Additionally, your ReadXml implementation should not rely on the wrapper element being named a particular way. The name is chosen by the serializer can vary.
It is permitted to assign IXmlSerializable content types polymorphically, for example, to data members of type Object. It is also permitted for the type instances to be null. Finally, it is possible to use IXmlSerializable types with object graph preservation enabled and with the NetDataContractSerializer. All these features require the WCF serializer to attach certain attributes into the wrapper element ("nil" and "type" in the XML Schema Instance namespace and "Id", "Ref", "Type" and "Assembly" in a WCF-specific namespace).
Before passing control to your ReadXml code, the deserializer examines the XML element, detects these special XML attributes, and acts on them. For example, if "nil" is true, a null value is deserialized and ReadXml is not called. If polymorphism is detected, the contents of the element are deserialized as if it was a different type. The polymorphically-assigned type’s implementation of ReadXml is called. In any case, a ReadXml implementation should ignore these special attributes because they are handled by the deserializer.
When exporting schema and an IXmlSerializable content type, the schema provider method is called. An XmlSchemaSet is passed to the schema provider method. The method can add any valid schema to the schema set. The schema set contains the schema that is already known at the time when schema export occurs. When the schema provider method must add an item to the schema set, it must determine whether an XmlSchema with the appropriate namespace already exists in the set. If it does, the schema provider method must add the new item to the existing XmlSchema. Otherwise, it must create a newXmlSchema instance. This is important if arrays of IXmlSerializable types are being used. For example, if you have anIXmlSerializable type that gets exported as type "A" in namespace "B", it is possible that by the time the schema provider method is called the schema set already contains the schema for "B" to hold the "ArrayOfA" type.
In addition to adding types to the XmlSchemaSet, the schema provider method for content types must return a non-null value. It can return an XmlQualifiedName that specifies the name of the schema type to use for the given IXmlSerializabletype. This qualified name also serves as the data contract name and namespace for the type. It is permitted to return a type that does not exist in the schema set immediately when the schema provider method returns. However, it is expected that by the time all related types are exported (the Export method is called for all relevant types on the XsdDataContractExporterand the Schemas property is accessed), the type exists in the schema set. Accessing the Schemas property before all relevant Export calls have been made can result in an XmlSchemaException. For more information about the export process, see Exporting Schemas from Classes.
The schema provider method can also return the XmlSchemaType to use. The type may or may not be anonymous. If it is anonymous, the schema for the IXmlSerializable type is exported as an anonymous type every time the IXmlSerializabletype is used as a data member. The IXmlSerializable type still has a data contract name and namespace. (This is determined as described in Data Contract Names except that the DataContractAttribute attribute cannot be used to customize the name.) If it is not anonymous, it must be one of the types in the XmlSchemaSet. This case is equivalent to returning the XmlQualifiedName of the type.
Additionally, a global element declaration is exported for the type. If the type does not have the XmlRootAttribute attribute applied to it, the element has the same name and namespace as the data contract, and its "nillable" property is true. The only exception to this is the schema namespace ("http://www.w3.org/2001/XMLSchema") – if the type’s data contract is in this namespace, the corresponding global element is in the blank namespace because it is forbidden to add new elements to the schema namespace. If the type has the XmlRootAttribute attribute applied to it, the global element declaration is exported using the following: ElementName, Namespace and IsNullable properties. The defaults with XmlRootAttributeapplied are the data contract name, a blank namespace and "nillable" being true.
The same global element declaration rules apply to legacy dataset types. Note that the XmlRootAttribute cannot override global element declarations added through custom code, either added to the XmlSchemaSet using the schema provider method or through GetSchema for legacy dataset types.
IXmlSerializable element types have either the IsAny property set to true or have their schema provider method return null.
Serializing and deserializing an element type is very similar to serializing and deserializing a content type. However, there are some important differences:
The schema exported for element types is the same as for the XmlElement type as described in an earlier section, except that the schema provider method can add any additional schema to the XmlSchemaSet as with content types. Using theXmlRootAttribute attribute with element types is not allowed, and global element declarations are never emitted for these types.
The IXmlSerializable interface and the XmlSchemaProviderAttribute and XmlRootAttribute attributes are also understood by the XmlSerializer . However, there are some differences in how these are treated in the data contract model. The important differences are summarized in the following list:
Be aware of these differences when creating types that are used with both serialization technologies.
When importing a schema generated from IXmlSerializable types, there are a few possibilities:
blabla...actually I understand little of all above words which come from MSDN. orz....any one who can give any comments to me .i will be apperiated for it .
but I just have done with some little code about this kind of data serialization which is dealed with DataContractSerializer background.
supposed we have a service contract below.
namespace CustomerLib { [ServiceContract] interface ICustomerServices { [OperationContract] string GetCustomer(CustomerImpIXmlSerializable c); } } [XmlSchemaProvider("GetSchema")] public class CustomerImpIXmlSerializable:IXmlSerializable { public string Id { get; set; } public string Name { get; set; } static string ns = "http://www.cnblogs.com/Charlesliu"; static string xs = "http://www.w3.org/2001/XMLSchema"; private CustomerImpIXmlSerializable _item; public CustomerImpIXmlSerializable LinkItem { get { return _item; } set { _item = value; } } public void WriteXml(XmlWriter writer) { writer.WriteStartElement("Id",ns);//must with the parameter ns. otherwise can not find the Id element from the xml. writer.WriteValue(Id); writer.WriteEndElement(); writer.WriteStartElement("Name" ,ns);//must with the ns parameter. writer.WriteValue(Name); writer.WriteEndElement(); } public void ReadXml(XmlReader reader) { CustomerImpIXmlSerializable item = new CustomerImpIXmlSerializable(); while (reader.IsStartElement()) { reader.MoveToContent(); reader.Read(); if (reader.IsStartElement("Id",ns)) { reader.MoveToContent(); item.Id = reader.ReadString(); reader.MoveToContent(); reader.ReadEndElement(); } else throw new XmlException("ExpectedElementMissing: Id element was expected."); if (reader.IsStartElement("Name",ns)) { reader.MoveToContent(); item.Name = reader.ReadString(); reader.MoveToContent(); reader.ReadEndElement(); } else throw new XmlException("ExpectedElementMissing: Title element was expected."); reader.MoveToContent(); reader.ReadEndElement(); } this._item = item; } public XmlSchema GetSchema() { return (null); }
//it is used for generate metadata for client side . in that .the client side can use this type in code public static XmlQualifiedName GetSchema(XmlSchemaSet schemaSet) { string schemaString = String.Format( "<xs:schema xmlns:tns='{0}' xmlns:xs='{1}' targetNamespace='{0}' elementFormDefault='qualified' attributeFormDefault='unqualified'>" + "<xs:complexType name='CustomerImpIXml'>" + "<xs:sequence>" + "<xs:element name='Id' type='xs:string' nillable='false'/>" + "<xs:element name='Name' type='xs:string' nillable='false'/>" + "</xs:sequence>" + "</xs:complexType>" + "</xs:schema>", ns, xs); XmlSchema schema = XmlSchema.Read(new StringReader(schemaString), null); schemaSet.XmlResolver = new XmlUrlResolver(); schemaSet.Add(schema); return new XmlQualifiedName("CustomerImpIXml", ns); } }
after that . by adding a service reference to wcf service. you can write code like this in main.
namespace testClient { class Program { static void Main(string[] args) { CustomerServicesClient client = new CustomerServicesClient(); CustomerImpIXml c = new CustomerImpIXml { Id = "1", Name = "xx" }; try { string sName = client.GetCustomer(c); Console.WriteLine(sName); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.ReadLine(); } } }