New Assembly breaks Deserializer, but all custom objects are in the same Assembly.

If I build an Assembly that contains my Serializing/DeSerializing static helper class, it breaks the functionality. There are custom objects being serialized, and two surrogates, all of which are contained within the Assembly as well. Mind you this does not result in a compile error, only in a runtime error.

I would very much like to do unit tests, and not having my stuff be in an accessible assembly has stopped that from happening, any help would be greatly appreciated.

Error:

SerializationException: Unable to load type CampaignData required for deserialization.
System.Runtime.Serialization.ObjectManager.DoFixups () (at <fb001e01371b4adca20013e0ac763896>:0)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize (System.Runtime.Remoting.Messaging.HeaderHandler handler, System.Runtime.Serialization.Formatters.Binary.__BinaryParser serParser, System.Boolean fCheck, System.Boolean isCrossAppDomain, System.Runtime.Remoting.Messaging.IMethodCallMessage methodCallMessage) (at <fb001e01371b4adca20013e0ac763896>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler, System.Boolean fCheck, System.Boolean isCrossAppDomain, System.Runtime.Remoting.Messaging.IMethodCallMessage methodCallMessage) (at <fb001e01371b4adca20013e0ac763896>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler, System.Boolean fCheck, System.Runtime.Remoting.Messaging.IMethodCallMessage methodCallMessage) (at <fb001e01371b4adca20013e0ac763896>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler, System.Boolean fCheck) (at <fb001e01371b4adca20013e0ac763896>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) (at <fb001e01371b4adca20013e0ac763896>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream) (at <fb001e01371b4adca20013e0ac763896>:0)
MemoryHandler.LoadCampaign (System.IO.FileInfo file) (at Assets/Scripts/Helpers/MemoryHandler.cs:30)
MenuBootstrap.Start () (at Assets/Scripts/UI/MenuBootstrap.cs:77)

Memory handler:

    public static CampaignData LoadCampaign(FileInfo file)
    {
        if (file == null) { return null; }
        BinaryFormatter formatter = GetBinaryFormatter();
        FileStream importedFile = File.Open(file.ToString(), FileMode.Open);

        object save = formatter.Deserialize(importedFile); // THIS IS WHERE THE ERROR IS.
        importedFile.Close();

        return (CampaignData)save;
    }

    public static void SaveCampaign(CampaignData data)
    {
        if (data == null) { return; }
        BinaryFormatter formatter = GetBinaryFormatter();

        string path = Application.persistentDataPath + "/" + data.ownerSteamId + data.ownerGameNumber + data.title + ".DPC";

        FileStream file = File.Create(path);
        formatter.Serialize(file, data);
        file.Close();
    }

    public static BinaryFormatter GetBinaryFormatter()
    {
        BinaryFormatter formatter = new BinaryFormatter();

        SurrogateSelector selector = new SurrogateSelector();

        AssetDictionarySurrogate assetDictionarySurrogate = new AssetDictionarySurrogate();
        DateTimeSurrogate dateTimeSurrogate = new DateTimeSurrogate();

        selector.AddSurrogate(typeof(Dictionary<string, AssetData>), new StreamingContext(StreamingContextStates.All), assetDictionarySurrogate);
        selector.AddSurrogate(typeof(DateTime), new StreamingContext(StreamingContextStates.All), dateTimeSurrogate);

        return formatter;
    }

And one of the surrogates (both are in the same assembly);

    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        Dictionary<string, AssetData> dict = (Dictionary<string, AssetData>)obj;
        List<AssetData> data = new List<AssetData>();
        List<string> ids = new List<string>();
        foreach(KeyValuePair<string, AssetData> pair in dict)
        {
            ids.Add(pair.Key);
            data.Add(pair.Value);
        }

        info.AddValue("data", data);
        info.AddValue("ids", ids);
    }

    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        Dictionary<string, AssetData> dict = (Dictionary<string, AssetData>)obj;
        List<AssetData> data = (List<AssetData>)info.GetValue("data", typeof(List<AssetData>));
        List<string> ids = (List<string>)info.GetValue("ids", typeof(List<string>));

        for (int i = 0; i < data.Count; i++)
        {
            dict.Add(ids_, data*);*_

}

obj = dict;
return obj;
}

Well, are the classes that you actually serialized still in the exact same assembly? If not this isn’t going to work. The BinaryFormatter stores the exact assembly name for all classes serialized.

Note that the BinaryFormatter is not meant for creating any kind of save files. Please read the BinaryFormatter security guide:

Warning

The BinaryFormatter type is dangerous
and is not recommended for data
processing. Applications should stop
using BinaryFormatter as soon as
possible, even if they believe the
data they’re processing to be
trustworthy. BinaryFormatter is
insecure and can’t be made secure.

Since the BinaryFormatter has a strong binding to the actual type and assembly It’s generally a bad choice for any kind of save format. It’s sensitive to any kind of changes to the serialized classes.

Apart from that, why do you use a surrogate in this case? The BinaryFormatter can serialize Dictionaries just fine.