Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Xml Serialization: can't (de)serialize an object that comes from another assembly

I'm trying to XML serialize/deserialize an object in C#. The catch is that this object is of a type that was not declared in the same assembly as the code that is invoking the serialization. Instead, it comes from an assembly loaded dynamically at runtime, ant thus it is unknown at compilation time to the code that is invoking the serialization.

The type I'm trying to serialize is this:

//Assembly = P.dll
namespace EDFPlugin.Plugin1
{
    [Serializable]
    [XmlRoot(Namespace = "EDFPlugin.Plugin1")] 
    [XmlInclude(typeof(Options))] 
    public class Options
    {
        private string _username;
        private string _password;

        public string Username {
            get { return _username; }
            set { _username = value;}
        }

        public string Password
        {
            get { return _password; }
            set { _password = value; }
        }
    }
}

As I mentioned before, the code I'm using to try to serialize/deserialize this object is located in an assembly that doesn't know about the Options type at compilation time (since it loads P.dll dynamically at runtime). Nevertheless, I managed to serialize the type correctly, by using this code:

//Assembly = A.exe (doesn't know about P.dll at compile time)
object value = GetOptions() //the actual type returned by this method is EDFPlugin.Plugin1.Options !!
XmlSerializer valueSerializer = new XmlSerializer(value.GetType());
valueSerializer.Serialize(writer, value);

basically, as you can see, by calling GetType() I can get around the issue of not having knowledge of the Options type at compilation time, everything works fine.

The problem arises when I try to deserialize:

//Assembly = A.exe (doesn't know about P.dll at compile time)
XmlSerializer valueSerializer = new XmlSerializer(typeof(object)); //have to use object, as I don't know the type in question...
object value = valueSerializer.Deserialize(reader); //throws exception

Since I don't know the type in question beforehand, I basically cannot properly setup the XmlSerializer. Using a generic object, as shown in the code above, generates an exception:

"<Options xmlns='EDFPlugin.Plugin1'> was not expected."

How can I solve this?

like image 928
Master_T Avatar asked Oct 19 '22 21:10

Master_T


1 Answers

A.exe (doesn't know about P.dll at compile time)

So if A.exe knows it at runtime, you shoud be able do load dynamically EDFPlugin.Plugin1

How about :

XmlSerializer valueSerializer = new XmlSerializer(Type.GetType("EDFPlugin.Plugin1.Options")); 
object value = valueSerializer.Deserialize(reader);

But what if I don't know that typename either?

It recommend to put a custom interface to distinguish option class to other class, then you'll be able to filter dynamically and load it with XmlSerializer.

public interface IAmPlugin
{

}

public class Options: IAmPlugin
{
      ......
}

Then :

Assembly assembly = ... // Your Assemblie which contains plugin 

// XmlSerializer needs all possible types to Deserialize an interface 
var possibleTypes = assembly.GetTypes().Where(t => t.IsClass && t.IsAssignableFrom(typeof(IAmPlugin))).ToArray(); 

XmlSerializer serializer = new XmlSerializer(typeof(IAmPlugin), possibleTypes);
object value = valueSerializer.Deserialize(reader);

This assumes you have a empty public constructors on Options class.

Why an interface instead of an Attribute? Because XmlSerializer handles only multiple interface type.

like image 68
Perfect28 Avatar answered Oct 21 '22 17:10

Perfect28