I am trying to remote an object from one executable to another.  The
first executable is a client of a service that is running within the
2nd executable.  This service takes in an object and modifies one of
it's members.  In order to properly support this, I was forced to make
a parent class of the object's class derive from
MarshalByRefObjectEverything seems to work fine except I get a
warning.

Here is an example of the warning:
Warning 12      Accessing a member on
'SharedStuff.SharedObject.m_nPublicIntMember' may cause a runtime
exception because it is a field of a marshal-by-reference class D:\DGB
\RemotingTest\Client\Client.cs  33      15      Client

To discover when an exception might occur, I wrote a test app (from
which the above warning was generated and for which I'll include the
code for below).  I have looked over the MSDN documentation and seen
their suggested manner for handling this warning.  However, in my
actual code (not the test app) the base class I altered to derive from
MarshalByRefObject is a base class for many different classes.  I'm
getting 100s of such warnings.  Thus, Microsoft's suggested solution
is pretty tedious and it isn't very robust (i.e. another developer
could come along and easily modify the code to re-create the problem
without realizing it).

So, I have a couple of questions.  The first is more of a general
question.

How is marshaling by reference ever useful when it is so prone to
causing an exception?

The second question is more important.

What other choice do I have to get the same behavior?  In other words,
how else can I do this?

Here is the sample code that illustrates my situation:

I have a solution with three projects in it which result in two
executables and one dll.  The dll contains the shared code between
them.  The executables are called Client and Server and are named
after their purpose:

Here's the Server:

namespace Server
{
        class ServerClass
        {
                static void Main( string[] args )
                {
                        Console.WriteLine( "Server App Running" );

                        RemotingConfiguration.RegisterWellKnownServiceType( 
typeof
(ServerService), "ServerService",    WellKnownObjectMode.Singleton );
                        Hashtable dictionary = new Hashtable();
                        dictionary["port"] = "9000";

                        BinaryServerFormatterSinkProvider serverProvider = new
BinaryServerFormatterSinkProvider();
                        serverProvider.TypeFilterLevel = TypeFilterLevel.Full;

                        TcpChannel channel = new TcpChannel( dictionary, new
BinaryClientFormatterSinkProvider(), serverProvider );

                        ChannelServices.RegisterChannel( channel, false );

                        Console.WriteLine( "Enter to close..." );
                        Console.ReadLine();
                }
        }

}

Here's the Client:

namespace Client
{
        class ClientClass
        {
                static void Main( string[] args )
                {
                        Console.WriteLine( "Client App Running" );
                        RemotingConfiguration.Configure( "XToolClient.config", 
false );

                        SharedObject so = new SharedObject();

                        ServerService ss = (ServerService)Activator.GetObject( 
typeof
( ServerService ), "tcp://localhost:9000/ServerService" );
                        ss.ChangeObject( so );

                        Console.WriteLine( string.Format( "{0}Pub Int: 
{1}{0}Contained Pub
Int:{2}{0}2DArraySize: [{3},{4}]{0}{0}2DArrayValues:{0}",
Environment.NewLine, so.m_nPublicIntMember,
so.m_ContainedClass.m_nPublicIntMember, so.m_2DArrayOfInts.GetLength
(0), so.m_2DArrayOfInts.GetLength(1) ) );

                        for ( int i=0 ; i<so.m_2DArrayOfInts.GetLength(0) ; ++i 
)
                        {
                                for ( int j=0 ; 
j<so.m_2DArrayOfInts.GetLength(1) ; ++j )
                                {
                                        Console.WriteLine( string.Format( 
"[{0},{1}] = {2}{3}", i, j,
so.m_2DArrayOfInts[i, j], Environment.NewLine ) );
                                }
                        }

                        string s = so.m_nPublicIntMember.ToString();
                }
        }
}


Here's the shared code:

namespace SharedStuff
{
        [Serializable]
        public class SharedObject : SharedObjectParent
        {
                public int m_nPublicIntMember = 0;
                public int[,] m_2DArrayOfInts = new int[2, 2] { { 0, 0 }, { 0,
0 } };

                public ContainedClass m_ContainedClass = new ContainedClass();
        }

        [Serializable]
        public class SharedObjectParent : MarshalByRefObject
        {
                public int m_nPubInt = 0;

                public ContainedByParentClass m_nCBPC = new 
ContainedByParentClass
();
        }

        [Serializable]
        public class ContainedClass
        {
                public int m_nPublicIntMember = 0;
        }

        [Serializable]
        public class ContainedByParentClass
        {
                public int m_nPubInt = 0;
        }

        public class ServerService : MarshalByRefObject
        {
                ServerService()
                {
                        Console.WriteLine( "ServiceService::ctor" );
                }

                public void ChangeObject( SharedObject soToModify )
                {
                        soToModify.m_nPublicIntMember = 1;
                        //string s = soToModify.m_nPublicIntMember.ToString();

                        string s2 = 
soToModify.m_ContainedClass.m_nPublicIntMember.ToString
();

                        int n1stDLength = soToModify.m_2DArrayOfInts.GetLength( 
0 );
                        soToModify.m_2DArrayOfInts[0, 0] = 5;
                        string s3 = soToModify.m_2DArrayOfInts[0, 0].ToString();
                        soToModify.m_2DArrayOfInts = new int[3, 2] { { 1, 1 }, 
{ 1, 1 },
{ 1, 1 } };
                }
        }
}


Finally, if you uncomment the line string s =
soToModify.m_nPublicIntMember.ToString() the client.exe crashes.

Yes, I know this example uses really poor design and programming
practices, but it is just an example.

Thanks in advance for any advice.

Reply via email to