Hassam
Hassam

Reputation: 69

XML De-serialization giving null WCF Objects

I am having an XML string like

<?xml version="1.0"?>
<FullServiceAddressCorrectionDelivery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <AuthenticationInfo xmlns="http://www.usps.com/postalone/services/UserAuthenticationSchema">
    <UserId xmlns="">FAPushService</UserId>
    <UserPassword xmlns="">Password4Now</UserPassword>
  </AuthenticationInfo>
</FullServiceAddressCorrectionDelivery>

In Order to map the nodes with Class, i am having the class structure in WCF like

[DataContract]
[Serializable]
public class FullServiceAddressCorrectionDelivery
{
    [XmlElement("AuthenticationInfo", Namespace = "http://www.usps.com/postalone/services/UserAuthenticationSchema")]
    [DataMember]
    public AuthenticationInfo AuthenticationInfo { get; set; }
}

[DataContract]
[Serializable]
public class AuthenticationInfo
{
    [DataMember]
    [XmlElement("UserId", Namespace = "")]
    public string UserId { get; set; }

    [DataMember]
    [XmlElement("UserPassword", Namespace = "")]
    public string UserPassword { get; set; }
}

For De-serialization , i used xmlserializer to De-serialize the object

XmlSerializer xs = new XmlSerializer(typeof(FullServiceAddressCorrectionDelivery));
var result = (FullServiceAddressCorrectionDelivery)xs.Deserialize(stream);

this method returned me a Null FullServiceAddressCorrectionDelivery object.. but when i used DataContractSerializer .. like

DataContractSerializer xs = new DataContractSerializer(typeof(FullServiceAddressCorrectionDelivery));
var result = (FullServiceAddressCorrectionDelivery)xs.ReadObject(stream);

then following exception came out..

Error in line 2 position 46. Expecting element 'FullServiceAddressCorrectionDelivery' from namespace 'http://schemas.datacontract.org/2004/07/WcfService1'.. Encountered 'Element' with name 'FullServiceAddressCorrectionDelivery', namespace ''.

i am stuck with this... i somehow with the help of RENE(StackOverFlow member) succeded to deserialize if the class was in same project .. but when i converted them to WCF Datacontracts.. i came across that issue ..... please guide me where i am doing wrong here...

Upvotes: 2

Views: 1304

Answers (1)

carlosfigueira
carlosfigueira

Reputation: 87228

Depending on how you want to use the data contract serializer (DCS) for that input, you may or may not be able to do that. The namespace of the data members in the DCS are defined by the namespace of the contract to which they belong, unless it's the root element (in which case the [DC] namespace also defines the namespace of the element).

Your root element, FullServiceAddressCorrectionDelivery, has one namespace in your sample XML (empty), and its member, AuthenticationInfo, has another (http://www.usps.com/postalone...). That means that unless you actually change how the serializer is created, you won't be able to use the DCS for this type.

The XmlSerializer (XS), however, should work just fine - members of the type can have different namespaces. As you can see in the code below, I can post the XML you provided verbatim to an operation which takes the FullServiceAddressCorrectionDelivery as an input, and the object is properly populated - you need to mark the operation (or the contract) with the [XmlSerializerFormat] attribute to get this behavior.

public class Post_6fc3a1bd_b3ca_48da_b4d2_35271135ed8a
{
    const string XML = @"<?xml version=""1.0""?>
 <FullServiceAddressCorrectionDelivery xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
 xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
   <AuthenticationInfo xmlns=""http://www.usps.com/postalone/services/UserAuthenticationSchema"">
     <UserId xmlns="""">FAPushService</UserId>
     <UserPassword xmlns="""">Password4Now</UserPassword>
   </AuthenticationInfo>
 </FullServiceAddressCorrectionDelivery>";

    [XmlRoot(ElementName = "FullServiceAddressCorrectionDelivery", Namespace = "")]
    public class FullServiceAddressCorrectionDelivery
    {
        [XmlElement("AuthenticationInfo", Namespace = "http://www.usps.com/postalone/services/UserAuthenticationSchema")]
        [DataMember]
        public AuthenticationInfo AuthenticationInfo { get; set; }
    }

    public class AuthenticationInfo
    {
        [XmlElement("UserId", Namespace = "")]
        public string UserId { get; set; }

        [XmlElement("UserPassword", Namespace = "")]
        public string UserPassword { get; set; }
    }

    [ServiceContract(Namespace = "")]
    public interface ITest
    {
        [XmlSerializerFormat]
        [OperationContract]
        FullServiceAddressCorrectionDelivery Echo(FullServiceAddressCorrectionDelivery input);
    }

    public class Service : ITest
    {
        public FullServiceAddressCorrectionDelivery Echo(FullServiceAddressCorrectionDelivery input)
        {
            return input;
        }
    }

    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
        host.Open();
        Console.WriteLine("Host opened");

        WebClient c = new WebClient();
        c.Headers[HttpRequestHeader.ContentType] = "text/xml";
        Console.WriteLine(c.UploadString(baseAddress + "/Echo", XML));

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}

For completeness sake, this is how you'd change the serializer creation (passing the root name and namespace) to be able to deserialize the XML you provided using the data contract serializer.

public class Post_6fc3a1bd_b3ca_48da_b4d2_35271135ed8a_b
{
    const string XML = @"<?xml version=""1.0""?>
 <FullServiceAddressCorrectionDelivery xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
 xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
   <AuthenticationInfo xmlns=""http://www.usps.com/postalone/services/UserAuthenticationSchema"">
     <UserId xmlns="""">FAPushService</UserId>
     <UserPassword xmlns="""">Password4Now</UserPassword>
   </AuthenticationInfo>
 </FullServiceAddressCorrectionDelivery>";

    [DataContract(Name = "FullServiceAddressCorrectionDelivery", Namespace = "http://www.usps.com/postalone/services/UserAuthenticationSchema")]
    public class FullServiceAddressCorrectionDelivery
    {
        [DataMember]
        public AuthenticationInfo AuthenticationInfo { get; set; }
    }

    [DataContract(Name = "AuthenticationInfo", Namespace = "")]
    public class AuthenticationInfo
    {
        [DataMember]
        public string UserId { get; set; }

        [DataMember]
        public string UserPassword { get; set; }
    }

    static string Serialize(object obj, bool useDataContractSerializer)
    {
        MemoryStream ms = new MemoryStream();
        XmlWriterSettings ws = new XmlWriterSettings
        {
            Indent = true,
            IndentChars = "  ",
            OmitXmlDeclaration = false,
            Encoding = new UTF8Encoding(false)
        };
        XmlWriter w = XmlWriter.Create(ms, ws);
        if (useDataContractSerializer)
        {
            var dcs = new DataContractSerializer(obj.GetType(), "FullServiceAddressCorrectionDelivery", "");
            dcs.WriteObject(w, obj);
        }
        else
        {
            new XmlSerializer(obj.GetType()).Serialize(w, obj);
        }

        w.Flush();
        string result = Encoding.UTF8.GetString(ms.ToArray());
        Console.WriteLine(result);

        w.Close();
        ms.Close();
        return result;
    }

    public static void Test()
    {
        Console.WriteLine("Serialization:");
        MemoryStream ms = new MemoryStream();
        XmlWriterSettings ws = new XmlWriterSettings
        {
            Indent = true,
            IndentChars = "  ",
            OmitXmlDeclaration = false,
            Encoding = new UTF8Encoding(false)
        };
        XmlWriter w = XmlWriter.Create(ms, ws);
        var dcs = new DataContractSerializer(typeof(FullServiceAddressCorrectionDelivery), "FullServiceAddressCorrectionDelivery", "");

        var obj = new FullServiceAddressCorrectionDelivery
        {
            AuthenticationInfo = new AuthenticationInfo
            {
                UserId = "FAPushService",
                UserPassword = "Password4Now"
            }
        };

        dcs.WriteObject(w, obj);

        w.Flush();
        string result = Encoding.UTF8.GetString(ms.ToArray());
        Console.WriteLine(result);
        Console.WriteLine();

        Console.WriteLine("Deserialization:");
        ms = new MemoryStream(Encoding.UTF8.GetBytes(XML));

        var obj2 = (FullServiceAddressCorrectionDelivery)dcs.ReadObject(ms);
        Console.WriteLine("{0} - {1}", obj2.AuthenticationInfo.UserId, obj2.AuthenticationInfo.UserPassword);
    }
}

Upvotes: 1

Related Questions