[en] Posted command returns before command is completely sent? (solved)

Topics: Technical Support
Aug 10, 2015 at 3:47 PM
Hello everybody,
at first I want to say "thank you" for this great framework, we really enjoy working with it.

We've got a little problem here and I wasn't able to find a "clean" solution for this.

I think our problem origins in the fact that we don't use the [Serializable] attribute within our source code. So we wrote a wrapper ZyanContainer which takes our command object and serializes it into a MemoryStream:
    [Serializable]
    public class ZyanCommandObjContainer : IDisposable
    {
        private MemoryStream _Data;

        public ZyanCommandObjContainer(CommandObject cmdObj)
        {
            SetCmdObj(cmdObj);
        }

        #region IDisposable Members

        public void Dispose()
        {
            _Data?.Dispose();
        }

        #endregion

        public void SetCmdObj(CommandObject cmdObj)
        {
            if (cmdObj == null) return;

            _Data = cmdObj.Serialize();
        }

        public CommandObject GetCmdObj()
        {
            if (_Data == null)
                return null;

            _Data.Position = 0;
            return SerializationUtils.Deserialize<CommandObject>(_Data);            
        }
    }
Our Proxy supports two methods: SendCommand() and PostCommand(). I guess since the signature of PostCommand is void, the framework sends the data to the receiving proxy and doesn't wait for any return value before returning from the function call.
    public interface IZyanProxy
    {
        ZyanCommandObjContainer SendCommand(ZyanCommandObjContainer container);

        void PostCommand(ZyanCommandObjContainer container);

        event Action<ZyanCommandObjContainer> OnNotifyAllClients;
    }
Since out ZyanContainer implements the IDisposable-Interface, our PostCommand-call within the sender looks like this:
using (var container = new ZyanContainer(cmd)){
    Proxy.PostCommand(container)
}
The odd thing is: I get an ObjectDisposedException on the receiving proxy trying to read the MemoryStream encapsuled within the ZyanContainer.
When I rewrite the PostCommand-call within the sender to
using (var container = new ZyanContainer(cmd)){
    Proxy.SendCommand(container)
}
everything works fine, except that we're returning a completely useless empty ZyanContainer back to the sender.

I assume that the container is disposed before it's been sent to the receiving proxy.

Any ideas on how to solve this?

And by the way: Since we're serializing twice (the container serializes the data using the DataContractSerializer and I assume that the Zyan framework serializes the ZyanContainer itself): Is there a way to tell the Zyan Framework to serialize the container using the DataContractSerializer?

Kind regards
Norbert
Coordinator
Aug 10, 2015 at 4:28 PM
Edited Aug 10, 2015 at 4:29 PM
Hi Norbert, thanks for you kind words!

The problem that is MemoryStream is not serializable, it is MarshalByRefObject.
So you're not actually sending your Data stream over the wire, instead, you are trying to access it remotely.

Just replace MemoryStream with byte[], get rid of IDisposable implementation, and you'll be fine:
[Serializable]
public class ZyanCommandObjContainer
{
    private byte[] data;

    public ZyanCommandObjContainer(CommandObject cmdObj)
    {
        SetCmdObj(cmdObj);
    }

    public void SetCmdObj(CommandObject cmdObj)
    {
        if (cmdObj == null) return;

        data = cmdObj.Serialize().ToArray();
    }

    public CommandObject GetCmdObj()
    {
        if (data == null)
            return null;

        using (var ms = new MemoryStream(data))
        {
            return SerializationUtils.Deserialize<CommandObject>(ms);
        }
    }
}
Regards, Alexey.
Coordinator
Aug 10, 2015 at 4:40 PM
Edited Aug 10, 2015 at 4:41 PM
Forgot to answer this:
 
I guess since the signature of PostCommand is void, the framework sends the data to the receiving proxy and doesn't wait for any return value before returning from the function call.
 
This is not the case. The proxy will always wait until the call is complete regardless of its return type.
Even if the return type is void, your method could throw an exception which should be routed back.

However if you really need this behavior, it's also possible to achieve (if your method is void and doesn't throw exceptions). This is called fire-and-forget pattern, and it can be enabled by decorating your void method with a OneWayAttribute like this:
public interface IMyServer
{
    [OneWay]
    void FireAndForget(int arg1, string arg2);
}
Marked as answer by yallie on 9/23/2015 at 11:49 PM
Aug 11, 2015 at 8:51 AM
Thanks a lot for yout input.

the byte[] implementation was our original one, I tried to get away from it since we're actually serializing our objects into a stream, copying this stream into a byte[] and then serializing the byte[] again... quite some overhead regarding memory consumption as well as performance.

The new information regarding MemoryStream confuses me a little bit... Some time ago, we wrote a serialization helper which should allow us to serialize datasets and datatables concurrently. This helper serialized the datatables into multiple MemoryStream which then were serialized into a single MemoryStream which could be saved into a file.

What also confuses me: If the framework awaits all methods of the proxy to return, then why was the container disposed before the receiving proxy was able to read the object from the container? The PostCommand method does exactly the same as the SendCommand method except for the missing return value. Since i rewrote the code to use SendCommand for both and return null in case of a posted command, everything works fine...
Coordinator
Aug 11, 2015 at 12:49 PM
Hi Norbert,
 
The new information regarding MemoryStream confuses me a little bit...
 
Ok, maybe it worth a bit of explaining the concepts of .NET remoting. There are two ways of
marshalling .NET objects across remoting borders: marshalling by reference and marshalling by value.

Classes marshalled by value are marked with Serializable attribute. Their instances are turned into bytes,
sent across the wire and re-instantiated on the other side of your channel. When you make a remote call,
you get a fresh copy of such an object on the remote side.

Classes marshalled by reference are derived from MarshalByRefObject class. Their instances are not copied
when you try to send them across the wire. When you make a remote call, the remote side gets a proxy
which allows calling methods of your object existing on your local side.

Now, have a look yourself at Stream class source code:
http://referencesource.microsoft.com/#mscorlib/system/io/stream.cs,f956b0c07e86df64

MemoryStream is derived from Stream, and Stream is derived from MarshalByRefObject. So, MemoryStream
is not serializable by definition. When you pass an instance of MemoryStream to you remote server, it is not
just copied there. It retains on the client side, where the server tries to access it using a proxy.
 
Some time ago, we wrote a serialization helper which should allow us to serialize datasets and datatables
concurrently. This helper serialized the datatables into multiple MemoryStream which then were serialized
into a single MemoryStream which could be saved into a file.
 
The ability to copy a stream to a file has nothing to do with Serializable concept. Serializable means
that an object is copied across the wire, MarshalByRefObject means that the object is not copied,
and the remote side just gets a proxy of it.
 
What also confuses me: If the framework awaits all methods of the proxy to return, then why was the
container disposed before the receiving proxy was able to read the object from the container?
 
At this point you probably can answer this question yourself. The server doesn't own your MemoryStream,
it owns nothing but a remote proxy of it. So it doesn't manage the lifetime of the stream and cannot use it
freely any time it wants. If by the moment your server reaches back your local memory stream it's already
disposed of on the local side (which can happen after your call), ObjectDisposedException is thrown.
 
the byte[] implementation was our original one, I tried to get away from it since we're actually serializing
our objects into a stream, copying this stream into a byte[] and then serializing the byte[] again... quite
some overhead regarding memory consumption as well as performance.
 
Did you really measure it? You actually add much-much more overhead with your MemoryStream
implementation, even if you find a way to overcome an ObjectDisposedException by holding on it a while.
You make your server accessing the memory stream remotely, which is painfully slow compared to sending
an array of bytes in a single roundtrip.

Regards, Alexey