views:

1320

answers:

2

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.)

using System;  
using System.IO;  
using System.ServiceModel.Description;  
using System.Text;  
using System.Xml;  
using System.Xml.Serialization;  
using System.ServiceModel;  
using SerializationTest.localhost;  

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" />
A: 

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" />
hurst
I think the issue is not with using XmlSerializer, but with the code generated for the proxy. In a real world scenario XML serialization will be handled by WCF, so you have no direct influence on the XmlSerializer being used.
csgero
Right. But the point is to be able to repurpose the data contract without having to modify it physically (whether by regenerating or manually editing it) and thus not interfering with the original intent of using it with WCF.
hurst
Sorry, you are right, I missed the point. There is also a somewhat simpler solution using the XmlSerializer constructor that takes an XmlRootAttribute parameter.
csgero
For my problem these overrides would be too common so I don't think this solution is quite what I want. I also think that when we switch to 2008 and start sharing types it will no longer matter. So even though I am not using this, I will mark it as the answer.
vfilby
A: 

== 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.

graffic