Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 640
Nikola Novak Avatar asked Nov 18 '11 14:11

Nikola Novak


2 Answers

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;
 }
}
like image 102
Nikola Novak Avatar answered Sep 20 '22 03:09

Nikola Novak


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")
like image 38
VMykyt Avatar answered Sep 24 '22 03:09

VMykyt