How to serialize/deserialize an object loaded from another assembly?

23,996

Solution 1

After poking around some more (i.e. googling the answer), I was able to resolve this. Here is the modified code:

Interfaces.cs (from a referenced assembly, Interfaces.dll)

public interface ISomeInterface
{
 ISettings Settings { get; set; }
}

public interface ISettings
{
 DateTime StartDate { get; }
}

SomeClass.cs (from a referenced assembly, SomeClass.dll)

public class SomeClass : ISomeInterface
{
 private MySettings settings = new Settings();

 public ISettings Settings
 {
  get { return (ISettings)settings; }
  set { settings = value as MySettings; }
 }
}

[Serializable]
public class MySettings : ISettings
{
 private DateTime dt;

 public MySettings() { dt = DateTime.Now; }

 public DateTime StartDate
 {
  get { return startFrom; }
  internal set { startFrom = value; }
 }
}

Serialization is done with:

public void SerializeState(string filename, ProgramState ps)
{
 Stream s = File.Open(filename, FileMode.Create);
 BinaryFormatter bFormatter = new BinaryFormatter();
 bFormatter.AssemblyFormat =
    System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
 bFormatter.Serialize(s, ps);
 s.Close();
}

And deserialization with:

public ProgramState DeserializeState(string filename)
{
 if (File.Exists(filename))
 {
  ProgramState res = new ProgramState();
  Stream s = File.Open(filename, FileMode.Open);
  BinaryFormatter bFormatter = new BinaryFormatter();
  bFormatter.AssemblyFormat =
    System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
  bFormatter.Binder = new MyBinder(); // MyBinder class code given below
  try
  {
   res = (ProgramState)bFormatter.Deserialize(s);
  }
  catch (SerializationException se)
  {
   Debug.WriteLine(se.Message);
  }
  s.Close();
  return res;
 }
 else return new ProgramState();
}

This class was added. This is the binder for the binary formatter:

internal sealed class MyBinder : SerializationBinder
{
 public override Type BindToType(string assemblyName, string typeName)
 {
  Type ttd = null;
  try
  {
   string toassname = assemblyName.Split(',')[0];
   Assembly[] asmblies = AppDomain.CurrentDomain.GetAssemblies();
   foreach (Assembly ass in asmblies)
   {
    if (ass.FullName.Split(',')[0] == toassname)
    {
     ttd = ass.GetType(typeName);
     break;
    }
   }
  }
  catch (System.Exception e)
  {
   Debug.WriteLine(e.Message);
  }
  return ttd;
 }
}

Solution 2

Do you want to (de)serialize using binary format? If no you may use the following:

P.S. This is not an solution but some kind of workaround.

Some assembly

public interface ISomeInterface { ISettings Settings { get; set; } }

public interface ISettings : ISerializable
{
    DateTime StartDate { get; }
}

public class SerializeHelper<T>
{
    public static void Serialize(string path, T item)
    {
        var serializer = new XmlSerializer(typeof(T));
        using (TextWriter textWriter = new StreamWriter(path, false, Encoding.UTF8))
        {
            serializer.Serialize(textWriter, T item);
        }
    }
}

SerializeHelper.Serialize(@"%temp%\sample.xml", instanceOfISomeInterface);

Some other assembly

public interface ISomeOtherInterface
{
ISettings Settings { get; set; }
}

public class DeSerializeHelper<T>
{
    public static T Deserialize(string path)
    {
   T instance = default(T);
   var serializer = new XmlSerializer(typeof(TestData));
   using (TextReader r = new StreamReader(path, Encoding.UTF8))
   {
      instance = (T)serializer.Deserialize(r);
   }
   return instance;
    }
}

ISomeOtherInterface instance = DeSerializeHelper.Deserialize<SomeOtherInterfaceImplementation>(@"%temp%\sample.xml")
Share:
23,996
Nikola Novak
Author by

Nikola Novak

Updated on January 12, 2020

Comments

  • Nikola Novak
    Nikola Novak over 4 years

    I want to serialize/deserialize an object that has been instantiated by another object loaded from an assembly:

    Interfaces.cs (from a referenced assembly, Interfaces.dll)

    public interface ISomeInterface
    {
     ISettings Settings { get; set; }
    }
    
    public interface ISettings : ISerializable
    {
     DateTime StartDate { get; }
    }
    

    SomeClass.cs (from a referenced assembly, SomeClass.dll)

    public class SomeClass : ISomeInterface
    {
     private MySettings settings = new Settings();
    
     public ISettings Settings
     {
      get { return (ISettings)settings; }
      set { settings = value as MySettings; }
     }
    }
    
    [Serializable]
    public class MySettings : ISettings
    {
     private DateTime dt;
    
     public MySettings() { dt = DateTime.Now; }
    
     protected MySettings(SerializationInfo info, StreamingContext context)
     {
      dt = info.GetDateTime("dt");
     }
    
     [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
     public void GetObjectData(SerializationInfo info, StreamingContext context)
     {
      info.AddValue("dt", dt);
     }
    
     public DateTime StartDate
     {
      get { return startFrom; }
      internal set { startFrom = value; }
     }
    }
    

    Startup project:

    [Serializable]
    public class ProgramState
    }
     public ISettings Settings { get; set; }
    }
    

    In the startup project, eventually I set Settings of an instance of ProgramState to Settings of SomeClass. I then go on to do the serialization using:

    public void SerializeState(string filename, ProgramState ps)
    {
     Stream s = File.Open(filename, FileMode.Create);
     BinaryFormatter bFormatter = new BinaryFormatter();
     bFormatter.Serialize(s, ps);
     s.Close();
    }
    

    This doesn't throw any exceptions. I deserialize with:

    public ProgramState DeserializeState(string filename)
    {
     if (File.Exists(filename))
     {
      ProgramState res = new ProgramState();
      Stream s = File.Open(filename, FileMode.Open);
      BinaryFormatter bFormatter = new BinaryFormatter();
      try
      {
       res = (ProgramState)bFormatter.Deserialize(s);
      }
      catch (SerializationException se)
      {
       Debug.WriteLine(se.Message);
      }
      s.Close();
      return res;
     }
     else return new ProgramState();
    }
    

    This throws an exception and the following appears in my Debug output:

    A first chance exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
    Unable to find assembly 'SomeClass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

    I'm sure that the assembly containing SomeClass has been loaded before the call to DeserializeState, so why is it throwing an exception that it is unable to find it?

    I've been looking at some tutorials, but the ones I was able to find only deal with classes from the same assembly (plus, my understanding of the serialization and deserialization process in .NET is minimal - a link to a detailed explanation might be helpful).

    In the meantime, is there any way to make this correctly deserialize the MySettings object?

  • Nikola Novak
    Nikola Novak over 12 years
    Hi, VMykyt. Thanks for the effort, but I do actually need it in binary.
  • Nikola Novak
    Nikola Novak about 11 years
    It's the type of object which needs to be deserialized. You can replace it with your own type, or Object if you need generality.