.NET smartcard - serialize/deserialize the remote

2019-06-04 04:22发布

问题:

I am using .NET smart card, it has the same concepts of .NET remoting.

So my smartcard (as a server) has this service:

public class MyService : MarshalByRefObject
{
     string a = "abC";

    public byte[] MySampleMethod()
    {
        MyService obj = new MyService();
        return help.ObjectToByteArray( obj);
    }}}

and this is ObjectToByteArray(obj)

public static byte[] ObjectToByteArray(MyService obj)
    {
        if (obj == null)
            return null;
        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream ms = new MemoryStream(0);
        bf.Serialize(ms, obj);
        return ms.ToArray();
    }

As for client :

    public static void Main()
    {
        // create and register communication channel
        APDUClientChannel channel = new APDUClientChannel();
        ChannelServices.RegisterChannel(channel);

        // get the referenc to remote object
        MyService service = (MyService)Activator.GetObject(typeof(MyService), URL);

        // invoke the remote method
        byte[] result = service.MySampleMethod();

        MyService obj = ByteArrayToObject(result);

        Console.WriteLine(result[0]);
        Console.ReadLine();
        // unregister the communication channel
        ChannelServices.UnregisterChannel(channel);
    }

ByteArrayToObject

    public static MyService ByteArrayToObject(byte[] arrBytes)
    {
        MemoryStream memStream = new MemoryStream(0);
        BinaryFormatter binForm = new BinaryFormatter();
        memStream.Write(arrBytes, 0, arrBytes.Length);

        memStream.Seek(0, SeekOrigin.Begin);
        //memStream.Position = 0;
        MyService obj = (MyService)binForm.Deserialize(memStream);
        return obj;
    }

The problem is when I want to Deserialize the object.

I test this string "ABCDE" , serialize it in the card and the result hex is :

1C-5D-D2-00-27-11-02-00-00-00-05-00-00-00-05-00-00-00-01-41-00-42-00-43-00-44-00‌​-45-00

WHILE the result when i serialize it on my pc is :

00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-00-06-01-00-00-00-05-41-42-43-44‌​-45-0B.

So on my PC application, deserializing the second one works well, but when i deserialize the first string (from smart card) I got :

"The input stream is not a valid binary format. The starting contents (in bytes) are: 1C-5D-D2-00-27-11-02-00-00-00-05-00-00-00-05-00-00 ..."

回答1:

Gemalto.NET Smart Card supports only marshalling by reference, so any primitive and struct types you have in the server can be accessed in client without the need of serialization because you already have the reference to the object through remote invocation:

so first register your service:

public class MyServer
    {
        /// <summary>
        /// specify the exposed remote object URI.
        /// </summary>
        private const string REMOTE_OBJECT_URI = "MyService.uri";

        /// <summary>
        /// Register the server onto the card.
        /// </summary>
        /// <returns></returns>
        public static int Main()
        {
            // Register the channel the server will be listening to.
            ChannelServices.RegisterChannel(new APDUServerChannel());

            // Register this application as a server            
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyService), REMOTE_OBJECT_URI, WellKnownObjectMode.Singleton);

            return 0;
        }
    }

and then define the service class, and you can return primitive types and struct, for gemalto docs:

Types that can be marshalled include the basic value types (byte, short, char, int, long, string, etc), structs, arrays of basic types, and MemoryStreams

public class MyService : MarshalByRefObject
    {
        public struct Person
        {
            public string name;
            public int id;

            public Person(int id, string name)
            {
                this.name = name;
                this.id = id;
            }

            public string getName()
            {
                return this.name;
            }

            public int getId()
            {
                return this.id;
            }
        }

        public string MySampleMethod()
        {
            return "This is return String";
        }

        public Person getPerson()
        {
            Person person = new Person(15, "Wajdy");
            return person;
        }
    }

Now in the client application, you will have the reference to service object and you can call the methods normally:

public class MyClient
    {
        private const string URL = "apdu://selfdiscover/MyService.uri";

        public static void Main()
        {
            // create and register communication channel
            APDUClientChannel channel = new APDUClientChannel();
            ChannelServices.RegisterChannel(channel);

            // get the referenc to remote object
            MyService service = (MyService)Activator.GetObject(typeof(MyService), URL);
            Console.WriteLine(service.MySampleMethod());

            MyService.Person person = service.getPerson();
            Console.WriteLine(person.getName());
            Console.WriteLine(person.getId());

            Console.ReadLine();

            // unregister the communication channel
            ChannelServices.UnregisterChannel(channel);
        }
    }