Creating XmlSerializer that serializes/deserializes derived types correctly
Asked Answered
M

2

1

I'm trying to create an XmlSerializer that serialize and deserializes derived types properly. Please take a look at the code below. Any assistance in using XmlAttributeOverrides ad extra types to create proper XmlSerializer and serialize an instance of GetVehicleResponse with VehicleObject as "SUV" object is greatly appreciated.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using InteractiveSoftworks.Framework.Xml;
using System.IO;

namespace DowncastTest
{
   [XmlType(Namespace="urn:Test/Service")]
   public class GetVehicleResponse
   {
      [XmlElement(IsNullable=true, Namespace="urn:Test")]
      public Vehicle VehicleObject;
   }

   [XmlType( Namespace = "urn:test" )]
   public class Vehicle
   {
      public string Model;
      public string Number { get; set; }
   }

   public class Car : Vehicle
   {
      public int Doors { get; set; }
   }

   public class SUV : Car
   {
      public int Engines { get; set; }
   }

   public class MotorCycle : Vehicle
   {
      public int Seats { get; set; }
   }

   public class SportsBike : MotorCycle
   {
      public int Mirrors { get; set; }
   }


   public class Program
   {
      static void Main( string[] args )
      {
         XmlAttributeOverrides overrides = new XmlAttributeOverrides();
         CreateAttributeOverrides( typeof( Car ), "urn:Test", overrides );
         CreateAttributeOverrides( typeof( SUV ), "urn:Test", overrides );
         CreateAttributeOverrides( typeof( MotorCycle ), "urn:Test", overrides );
         CreateAttributeOverrides( typeof( SportsBike ), "urn:Test", overrides );

         Type[] extraTypes = new Type[] { typeof( Car ), typeof( SUV ), typeof( MotorCycle ), typeof( SportsBike ) };

         XmlSerializer xs = new XmlSerializer( typeof( GetVehicleResponse ), overrides, extraTypes, new XmlRootAttribute() { ElementName = "GetVehicleResponse", Namespace = "urn:Test" }, "urn:Test" );

         MemoryStream ms = new MemoryStream();
         xs.Serialize( ms, new GetVehicleResponse() { VehicleObject = new SUV() { Number = "AP29", Model = "2011", Doors = 4, Engines = 2 } } );

         string s = Encoding.UTF8.GetString( ms.GetBuffer() );

         Console.WriteLine( s );

         Console.WriteLine( "Done..." );
         Console.ReadKey();
      }

      internal static void CreateAttributeOverrides( Type type, string projectNamespace, XmlAttributeOverrides overrides )
      {
         // redirect the type if no explicit XmlAttributeType namespace has been provided
         //
         XmlAttributes typeAttributes = new XmlAttributes( type );
         XmlTypeAttribute typeAttribute = null;

         if ( typeAttributes.XmlType != null ) // inherit existing methodType attributes if any
         {
            if ( string.IsNullOrEmpty(typeAttributes.XmlType.Namespace) ) // only set the namespace if it isn't already defined
            {
               typeAttribute = typeAttributes.XmlType;
               typeAttribute.Namespace = projectNamespace;
            }
         }
         else
         {
            string rootNamespace = string.Empty;

            // if type defined Xml Root Attributes then get the namespace and add to type attributes
            //
            if ( typeAttributes.XmlRoot != null )
               rootNamespace = typeAttributes.XmlRoot.Namespace;

            if ( string.IsNullOrEmpty( rootNamespace ) )
               rootNamespace = projectNamespace;

            typeAttribute = new XmlTypeAttribute() { Namespace = rootNamespace };

         }

         if ( typeAttribute != null )
            overrides.Add( type, new XmlAttributes() { XmlType = typeAttribute } );  // use a fresh XmlAttributes as we only want to globally override XmlTypeAttribute
      }

   }
}
Mcwilliams answered 9/5, 2011 at 18:21 Comment(0)
A
0

I think you are looking for the XmlIncludeAttribute

Applause answered 9/5, 2011 at 20:13 Comment(0)
I
0

As an alternative approach, you can use a form of the XmlSerializer that supports an extra types parameter that you can use to specify derived types: From the doc:

You can also use the extraTypes parameter to specify types derived from a base class.

This works fine in my experience, but is not perfect for every situation since you need to be prepared to address potential issues in Microsoft's implementation. See the section on Dynamically Generated Assemblies in the XmlSerializer doc for details.

Intend answered 13/6, 2011 at 17:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.