Question

Using .Net 3.0 and VS2005.

The objects in question are consumed from a WCF service then serialized back into XML for a legacy API. So rather than serializing the TestObject, it was serializing .TestObject which was missing the [XmlRoot] attribute; however, all the [Xml*] attributes for the child elements were in the generated proxy code so they worked just fine. So all the child elements worked just fine, but the enclosing element did not because the [XmlRoot] attribute wasn't included in the generated proxy code. The original object that included the [XmlRoot] attribute serializes fine manually.

Can I have the proxy code include the [XmlRoot] attribute so the generated proxy class serializes correctly as well? If I can't do that I suspect I'll have to use [XmlType] but that causes minor havoc requiring me to change other components so I would prefer the former. I also want to avoid having to manually edit the autogenerated proxy class.

Here is some sample code (I have included the client and the service in the same app because this is quick and for test purposes. Comment out the service referencing code and add the service reference while running the app, then uncomment the service code and run.)

namespace SerializationTest {  
  class Program {  
    static void Main( string[] args ) {  

        Type serviceType = typeof( TestService );  
        using (ServiceHost host = new ServiceHost(   
            serviceType,   
            new Uri[] {   
                new Uri( "http://localhost:8080/" )  
            }  

        ))
        {

            ServiceMetadataBehavior behaviour = new ServiceMetadataBehavior();  
            behaviour.HttpGetEnabled = true;  
            host.Description.Behaviors.Add( behaviour );  

            host.AddServiceEndpoint( serviceType, new BasicHttpBinding(), "TestService" );  
            host.AddServiceEndpoint( typeof( IMetadataExchange ), new BasicHttpBinding(), "MEX" );  


            host.Open();  

            TestServiceClient client = new TestServiceClient();  
            localhost.TestObject to = client.GetObject();  

            String XmlizedString = null;  
            using (MemoryStream memoryStream = new MemoryStream()) {
                XmlSerializer xs = new XmlSerializer( typeof( localhost.TestObject ) );  
                using (XmlWriter xmlWriter = XmlWriter.Create(memoryStream)) {
                    xs.Serialize( xmlWriter, to );  
                    memoryStream = (MemoryStream)xmlWriter.BaseStream;  
                    XmlizedString = Encoding.UTF8.GetString( memoryStream.ToArray() );  
                    Console.WriteLine( XmlizedString );  
                }    
            }    
        }

        Console.ReadKey();  
    }  
}  

[Serializable]  
[XmlRoot( "SomethingElse" )]  
public class TestObject {  

    private bool _worked;  

    public TestObject() { Worked = true; }  

    [XmlAttribute( AttributeName = "AttributeWorked" )]  
    public bool Worked {  
        get { return _worked; }  
        set { _worked = value; }  
    }  
}  

[ServiceContract]  
public class TestService {  

    [OperationContract]  
    [XmlSerializerFormat]  
    public TestObject GetObject() {  
        return new TestObject();  
    }  
  }  
}  

Here is the Xml this generates.

<?xml version="1.0" encoding="utf-8"?>
<TestObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" AttributeWorked="true" /> 
Was it helpful?

Solution

I found someone who provides a means to solve this situation:

Matevz Gacnik's Weblog

Using that approach of XmlAttributeOverrides, I wrote the following:

    private static XmlSerializer GetOverridedSerializer()
    {
        // set overrides for TestObject element
        XmlAttributes attrsTestObject = new XmlAttributes();
        XmlRootAttribute rootTestObject = new XmlRootAttribute("SomethingElse");
        attrsTestObject.XmlRoot = rootTestObject;

       // create overrider
       XmlAttributeOverrides xOver = new XmlAttributeOverrides();
       xOver.Add(typeof(localhost.TestObject), attrsTestObject);

       XmlSerializer xSer = new XmlSerializer(typeof(localhost.TestObject), xOver);
       return xSer;
    }

Just put that method in the Program class of your example, and replace the following line in Main():

        //XmlSerializer xs = new XmlSerializer(typeof(localhost.TestObject));
        XmlSerializer xs = GetOverridedSerializer();

And then run to see the results.

Here is what I got:

<?xml version="1.0" encoding="utf-8"?><SomethingElse xmlns:xsi="http://www.w3.o
rg/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Attribu
teWorked="true" />

OTHER TIPS

== IF ==

This is only for the XmlRoot attribute. The XmlSerializer has one constructor where you can specify the XmlRoot attribute.

Kudos to csgero for pointing it. His comment should be the solution.

XmlSerializer Constructor (Type, XmlRootAttribute)

Initializes a new instance of the XmlSerializer class that can serialize objects of the specified type into XML documents, and deserialize an XML document into object of the specified type. It also specifies the class to use as the XML root element.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top