SerializationException: Invalid binary format when accessing a MarshalByRefObject

Hello!

We are trying to send constantly a jagged array of floats to a Unity app from another C# application.

We got a C# dll that uses a MarshalByRefObject and opens an Ipc channel for a simple test server app and a simple test client app. Both apps are able to share data. However, we are getting an error when trying to substitute the client app with the Unity app. This is what the console says:

SerializationException: Invalid binary format
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadRefTypeObjectInstance (System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:281)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObject (BinaryElement element, System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:179)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadNextObject (BinaryElement element, System.IO.BinaryReader reader) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:130)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectGraph (BinaryElement elem, System.IO.BinaryReader reader, Boolean readHeaders, System.Object& result, System.Runtime.Remoting.Messaging.Header[]& headers) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:104)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.NoCheckDeserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/BinaryFormatter.cs:179)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/BinaryFormatter.cs:136)
System.Runtime.Remoting.Channels.Ipc.Win32.IpcTransport.Read (ITransportHeaders& headers, System.IO.Stream& responseStream)
System.Runtime.Remoting.Channels.Ipc.Win32.IpcClientChannelSink.ProcessMessage (IMessage msg, ITransportHeaders requestHeaders, System.IO.Stream requestStream, ITransportHeaders& responseHeaders, System.IO.Stream& responseStream)
System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage (IMessage msg)

And this after that:

NamedPipeException: The pipe is being closed.

System.Runtime.Remoting.Channels.Ipc.Win32.NamedPipeSocket.Send (System.Byte[] buffer, Int32 offset, Int32 count)
System.Runtime.Remoting.Channels.Ipc.Win32.NamedPipeStream.Write (System.Byte[] buffer, Int32 offset, Int32 count)
System.Runtime.Remoting.Channels.Ipc.Win32.IpcTransport.Write (ITransportHeaders header, System.IO.Stream requestStream)
System.Runtime.Remoting.Channels.Ipc.Win32.IpcClientChannelSink.ProcessMessage (IMessage msg, ITransportHeaders requestHeaders, System.IO.Stream requestStream, ITransportHeaders& responseHeaders, System.IO.Stream& responseStream)
System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage (IMessage msg)

This only happens when trying to access the shared object, any other function within the dll works just fine, so the dll is being included and accessed correctly. Also we trying downgrading the C# version of the dll and test apps from 3.5 to 2.0 and changing the architecture from Any CPU to x64 and x86. The issue remains.

This is a new topic for me so my only guess is that the dll is serializing the data before Unity receives it and Unity doesn’t recognize the format?

If you need the source code of the dll or the test apps, please let me know.

I would really appreciate your help!

Thank you!

The issue happens when deserializing? Do I understand it correctly?
Yes, seeing the serialization code would help.

I am not really sure because we never specifically coded a serialization process. Here is the dll code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;

namespace U2SDLL
{
    /// <summary>
    /// shared object
    /// </summary>
    public class U2SSharedObject : MarshalByRefObject
    {
        public Int32 IntegerValue { get; set; }
        public Single[] DataArray { get; set; }

        /// <summary>
        /// iitialize array
        /// </summary>
        /// <param name="arraysize">Single array size</param>
        /// <returns>=true:succeeded =false:failed</returns>
        public Boolean Init(Int32 arraysize)
        {
            IntegerValue = 0;
            DataArray = new Single[arraysize];
            return true;
        }

        /// <summary>
        /// avoid disconnection
        /// </summary>
        public override object InitializeLifetimeService()
        {
            return null;
        }
    }

    /// <summary>
    /// server class
    /// </summary>
    public class U2SServer
    {
        public U2SSharedObject SharedObject { get; set; }
   
        /// <summary>
        /// constructor
        /// </summary>
        public U2SServer()
        {
            // Create server channel
            IpcServerChannel channel = new IpcServerChannel("ipcU2SDLL");
   
            // Registratio channel
            ChannelServices.RegisterChannel(channel, false);
   
            // Create object and sharing
            SharedObject = new U2SSharedObject();
            SharedObject.Init(10000);
            RemotingServices.Marshal(SharedObject, "ipcRemoteObject", typeof(U2SSharedObject));
        }


        /// <summary>
        /// get integer value
        /// </summary>
        public Int32 GetIntegerValue()
        {
            return SharedObject.IntegerValue;
        }

        /// <summary>
        /// set integer value
        /// </summary>
        public void SetIntegerValue(Int32 value)
        {
            SharedObject.IntegerValue = value;
        }

        /// <summary>
        /// get float value array
        /// </summary>
        public Single[] GetFloatArray()
        {
            return SharedObject.DataArray;
        }

        /// <summary>
        /// set float value array
        /// </summary>
        public void SetFloatArray(Single[] data)
        {
            //Create clone data
            SharedObject.DataArray = (Single[])data.Clone();
        }
    }

    /// <summary>
    /// client class
    /// </summary>
    public class U2SClient
    {
        public U2SSharedObject SharedObject { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        public U2SClient()
        {
            // Create client channel
            IpcClientChannel channel = new IpcClientChannel();

            // Registratio channel
            ChannelServices.RegisterChannel(channel, false);

            // Get remote object
            SharedObject = Activator.GetObject(typeof(U2SSharedObject), "ipc://ipcU2SDLL/ipcRemoteObject") as U2SSharedObject;
        }


        /// <summary>
        /// get integer value
        /// </summary>
        public Int32 GetIntegerValue()
        {
            return SharedObject.IntegerValue;
        }

        /// <summary>
        /// set integer value
        /// </summary>
        public void SetIntegerValue(Int32 value)
        {
            SharedObject.IntegerValue = value;
        }

        /// <summary>
        /// get float value array
        /// </summary>
        public Single[] GetFloatArray()
        {
            return SharedObject.DataArray;
        }

        /// <summary>
        /// set float value array
        /// </summary>
        public void SetFloatArray(Single[] data)
        {
            //Create clone data
            SharedObject.DataArray = (Single[])data.Clone();
        }

        public string TestDLLConnection()
        {
            return "DLL says hello!";
        }
    }
}

I am assuming that the ipc channel needs to serializate the code in order to send it, so maybe the serialization is done deep inside the SharedObject code. Within Unity we just create a “U2SClient” and try to access the “GetFloatArray” function.