4
votes

I have a WCF service which accepts a string as a paramter for one of its operation contracts. This string however has xml content in it.

I need to convert this into a class that is marked as a DataContract but is not exposed to the outside world.

I need to use the DataContractSerializer because the class members have the [DataMember] attribute set to a different name. Eg: the property Phone has the DataMember Name set as "Telephone", so when i deserialize the xmldocument using the normal serializer, i get an error as the deserializer looks for the Phone element which does not exist.

How do i de-serialize an XmlDocument using the DataContractSerializer? One constraint though is i cannot save the xmldocument to a file.

EDIT: Found an excellent article on serialization and de-serialization using DataContractSerializer here.

My client code:

string xmldata = "<Customer> + 
                System.Environment.NewLine+ 
                "<Age>1</Age>"+
                System.Environment.NewLine+
                "<BirthDate>1900-01-01T01:01:01.0000000-05:00</BirthDate>" + 
                System.Environment.NewLine+
                "<FistName>John</FistName>"+
                System.Environment.NewLine +
                "<LastName>Doe</LastName>" +
                System.Environment.NewLine +
                "</Customer>";

doc.LoadXml(xmldata); 
Service1Client a = new Service1Client();
a.GetData(doc.OuterXml.ToString());

My service code:

public string GetData(string per)
{
    string xmldata = per;
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(xmldata);
    XmlDemo.Person a = Person.Create();

    DataContractSerializer ser = new DataContractSerializer(a.GetType());
    StringWriter stringWriter = new StringWriter();
    XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);
    xmlDoc.WriteTo(xmlWriter);

    MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(stringWriter.ToString()));
    stream.Position = 0;
    XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
    Person myContact = (Person)ser.ReadObject(reader, true);

    return string.Empty; 

}

My DataContract:

[Serializable]
[DataContract(Name = "Customer")]
public class Person
{
    private Person() {}
    [DataMember(Name = "FistName")]
    public string FName { get; set; }
    [DataMember(Name = "LastName")]
    public string LName { get; set; }
    [DataMember(Name = "Age")]
    public int Age { get; set; }
    [DataMember(Name = "BirthDate")]
    public DateTime DOB { get; set; }

    public static Person Create()
    {
        return new Person();
    }
}

I get this error at Person myContact = (Person)ser.ReadObject(reader, true);

Error in line 1 position 11. Expecting element 'Customer' from namespace 'http://schemas.datacontract.org/2004/07/XmlDemo'.. Encountered 'Element'  with name 'Customer', namespace ''.
2
Could you please rephrase the question and be alittle more specific. I don't understand what you want - alanquillin

2 Answers

3
votes

Deserialize from string straight way

MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes("<myXml />"));
stream.Position = 0;
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
MyContact myContact = (MyContact)ser.ReadObject(reader, true);

Deserialize from XmlDocument

StringWriter stringWriter = new StringWriter();
XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);
xmlDoc.WriteTo(xmlWriter);

MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(stringWriter.ToString()));
stream.Position = 0;
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
MyContact myContact = (MyContact)ser.ReadObject(reader, true);
1
votes

Is this your service? If so, then don't send or receive XML in a string parameter, since they're not the same thing.

Also, though you haven't exposed the DataContract into which you want to deserialize this XML to the world, you pretty much have done so by exposing the XML. It's largely the same effect. So you should instead create a DataContract class that has no behavior associated with it, then expose that in your ServiceContract. If you need to use it internally as data in a class with behavior, then copy the data into a new instance of your internal class, that you never expose.


I still recommend you stop this silliness with copying XML into and out of strings. Still, based on the code and exception you posted:

Why do this

XmlDemo.Person a = Person.Create();

and then wipe it out when you deserialize?

XmlDemo.Person a;

is adequate. Then use typeof(XmlDemo.Person) instead of a.GetType().

Also, is the Person class you posted the exact same "XmlDemo.Person" class? I'm very curious to know where that namespace comes from. To remove my uncertainty, try changing the [DataContract] attribute to say Namespace=String.Empty (or maybe Namespace=null).

Finally, have you ever heard the one about the developer who didn't call Dispose on instances of classes that implement IDisposable?