Question

I am migrating an old NETCF 2.0 Application which uses webservices to NETCF 3.5. The webservice of the foreign server remains the same without changes. Also I newly generated Reference.cs using VS 2008 Command Prompt - and was excited to see the same result as using VS 2005.

My question relates to namespace definition at the root tag by a class which is defined by webservice. The java webservice serializes it with xmlns attribute and XmlSerializer.Deserialize() of NETCF 3.5 blames about this attribute throwing an InvalidOperationException. Using this XML and XmlSerializer.Deserialize() with NETCF 2.0 works as expected. The Object gets deserialized to memory.

Let a few code snippets make things clear.

Exception

InvalidOperationException-There is an error in XML document (2, 2).
InnerException: InvalidOperationException-<InstallDirective xmlns='java:my.foreign.namespace'> was not expected. 
  at System.Xml.Serialization.XmlSerializer.resolveDeserializingType(XmlReader reader, XmlSerializationReader serialReader, Boolean soap12)
  at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
  at System.Xml.Serialization.XmlSerializer.Deserialize(Stream stream)
  at My.Neat.Software.Bug.Test()

generated Reference.cs (excerpt)

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="java:my.foreign.namespace")]
public partial class InstallDirective {
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
    public System.Nullable<System.DateTime> Date;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
    public JustAnotherThing JustAnotherThing;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
    public System.Nullable<short> Oid;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
    public string Filename;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
    public string Version;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
    public string Dir;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
    public string Instructions;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("Scripts", IsNullable=true)]
    public Script[] Scripts;
}

the XML from webservice

<?xml version="1.0" encoding="utf-8"?>
<InstallDirective xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="java:my.foreign.namespace">
    <Date>2014-02-11T13:31:49.238+01:00</Date>
    <JustAnotherThing>
        <FileName>MyFunnyFile.txt</CabFileName>
        <Checksum>e759af8bd5787e3f8d62245a7d6aa73d</Checksum>
        <FileExists xsi:nil="true" />
        <Name>MyFunnyFile</Name>
        <Version>1.2</Version>
        <Path xsi:nil="true" />
        <DependsOn xsi:nil="true" />
        <RegistryPath xsi:nil="true" />
    </JustAnotherThing>
    <Oid>1</Oid>
    <Filename>MyFunnyFile.txt</Filename>
    <Version>1.2</Version>
    <Dir>\My\Path\To\Files</Dir>
    <Instructions xsi:nil="true" />
    <Scripts xsi:nil="true" />
</InstallDirective>

the code snippet which throws the exception

FileInfo directiveFile = new FileInfo(@"\tmp\install\funnyInstallDirective.xml");
XmlSerializer xmlSerializer = new XmlSerializer(typeof(InstallDirective));
TextReader reader = new StreamReader(directiveFile.OpenRead());
InstallDirective installDirective = (InstallDirective)xmlSerializer.Deserialize(reader); // BAM!

Thanks for your help!

Was it helpful?

Solution

Indeed the XmlSerializer implementation of .Net Compact Framework 2.0 and 3.5 differs. The solution to this "new" behaviour is easy as well. Because the XmlSerializer which - in my case - serializes XML as a "fragment", we need to declare the XmlRootAttribute. This is due to missing XmlRootAttribute annotation of the type to be serialized within the Reference.cs. To be backward compatible with XML serialized by NETCF 2.0 implementation, we need to add the namespace by definition of InstallDirective (Reference.cs). Unfortunately I found no programmatically way to get this.

Before:

XmlSerializer xmlSerializer = new XmlSerializer(typeof(InstallDirective));
FileStream file = File.Create(@"\tmp\install\funnyInstallDirective.xml");
TextWriter writer = new StreamWriter(file);
xmlSerializer.Serialize(writer, installDirective);

After:

XmlRootAttribute att = new XmlRootAttribute(typeof(InstallDirective).Name);
att.Namespace = "java:my.foreign.namespace";
XmlSerializer xmlSerializer = new XmlSerializer(typeof(InstallDirective), att);
FileStream file = File.Create(@"\tmp\install\funnyInstallDirective.xml");
TextWriter writer = new StreamWriter(file);
xmlSerializer.Serialize(writer, installDirective);

Credits to ta.speot.is who answered the question here.

[UPDATE] Of course you can beautify it by using the annotated XmlTypeAttribute of the web service type. It will look this way.

XmlTypeAttribute ta = (XmlTypeAttribute)Attribute.GetCustomAttribute(typeof(InstallDirective), typeof(XmlTypeAttribute));
XmlRootAttribute att = new XmlRootAttribute(typeof(InstallDirective).Name);
att.Namespace = ta.Namespace;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(InstallDirective), att);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top